samagotchi 0.117.0 → 0.119.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +31 -2
- data/docs/cli.md +29 -0
- data/docs/configuration.md +2 -0
- data/docs/plugins.md +22 -0
- data/lib/samagotchi/bundles/claude-peer/manifest.yml +3 -3
- data/lib/samagotchi/bundles/claude-peer/scripts/chi-peer-SKILL.md +48 -0
- data/lib/samagotchi/bundles/claude-peer/scripts/pair +73 -16
- data/lib/samagotchi/bundles/system/manifest.yml +1 -1
- data/lib/samagotchi/version.rb +1 -1
- data/lib/samagotchi/web/public/apple-touch-icon.png +0 -0
- data/lib/samagotchi/web/public/favicon.svg +1 -1
- data/lib/samagotchi/web/public/icons/chi-180.png +0 -0
- data/lib/samagotchi/web/public/icons/chi-192.png +0 -0
- data/lib/samagotchi/web/public/icons/chi-512.png +0 -0
- data/lib/samagotchi/web/public/index.html +12 -2
- data/lib/samagotchi/web/public/manifest.webmanifest +1 -1
- data/lib/samagotchi/web/public/tokens.css +2 -2
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 67772cbed2c590109f257a85de25cc009250b6fb3a78c1bf4e1b2194561846b7
|
|
4
|
+
data.tar.gz: ac023d3b8f28c1196b234e528eae9faf9947181ee6f44111c7f00723eb92b196
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e818ad092946ec8ca8d1765079824a0cd7f540734fc9ad52b1a28d2ad70f12be7ff21324f348eda1461474d2924e99f97fa5f45fe25e11e16cc65c7e2a7f63af
|
|
7
|
+
data.tar.gz: 2c852f4b48dcee1bd4c742eb3acdbe34ee802a53407b562b09398b13be34a9de3bcbdeebb058781691c07a7c696797ea660133e84155ccb2247ab6e9e5f72596
|
data/CHANGELOG.md
CHANGED
|
@@ -5,9 +5,36 @@ format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
|
|
|
5
5
|
versions follow [Semantic Versioning](https://semver.org/); before 1.0, config
|
|
6
6
|
and commands may change between minor versions. How releases are made:
|
|
7
7
|
[docs/releasing.md](docs/releasing.md).
|
|
8
|
-
|
|
9
8
|
## [Unreleased]
|
|
10
9
|
|
|
10
|
+
## [0.119.0] - 2026-10-26
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- claude-peer (0.4.3): `pair --inbox-socket PATH` pairs both ways with chi on
|
|
15
|
+
another machine through an `ssh -R` forward of Claude's socket
|
|
16
|
+
([docs/plugins.md](docs/plugins.md)); docs/cli.md: remote sessions through an
|
|
17
|
+
SSH tunnel. Update with `chi update`.
|
|
18
|
+
|
|
19
|
+
## [0.118.0] - 2026-10-26
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- chi's icon (the browser tab and the Home Screen app) is flat: a system-blue χ on a graphite tile, no gradient. On a
|
|
24
|
+
phone, remove the Home Screen app and add it again to see it: iOS keeps the old icon.
|
|
25
|
+
- chi web's blues match the icon: links, the active card and the Send button use Apple's system blue in both themes,
|
|
26
|
+
and the page background keeps only its faint blue glow (the purple one is gone).
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- chi web's session bar stops squeezing its meta row into a narrow column in a small window: the bar's own actions
|
|
31
|
+
(continue, archive, stop session, delete) take a line of their own when they cannot sit beside the row, the folder
|
|
32
|
+
takes at most a third of it and a chip at most 30% (cut with "…", the full text in the tooltip), so a session with a
|
|
33
|
+
long model name and a long folder reads two lines at 760 px instead of five. Phones (≤ 600 px) scroll the row as
|
|
34
|
+
before.
|
|
35
|
+
|
|
36
|
+
Update with `chi update` (the system bundle 0.118.0), then restart `chi web`.
|
|
37
|
+
|
|
11
38
|
## [0.117.0] - 2026-10-26
|
|
12
39
|
|
|
13
40
|
### Added
|
|
@@ -4427,7 +4454,9 @@ and long-lived sessions.
|
|
|
4427
4454
|
- A macOS desktop helper (`chi desktop install`): a "Send to chi" Service and a
|
|
4428
4455
|
hotkey panel that send selected text or the clipboard to your sessions.
|
|
4429
4456
|
|
|
4430
|
-
[Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.
|
|
4457
|
+
[Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.119.0...HEAD
|
|
4458
|
+
[0.119.0]: https://github.com/dm1try/samagotchi/compare/v0.118.0...v0.119.0
|
|
4459
|
+
[0.118.0]: https://github.com/dm1try/samagotchi/compare/v0.117.0...v0.118.0
|
|
4431
4460
|
[0.117.0]: https://github.com/dm1try/samagotchi/compare/v0.116.0...v0.117.0
|
|
4432
4461
|
[0.116.0]: https://github.com/dm1try/samagotchi/compare/v0.115.0...v0.116.0
|
|
4433
4462
|
[0.115.0]: https://github.com/dm1try/samagotchi/compare/v0.114.0...v0.115.0
|
data/docs/cli.md
CHANGED
|
@@ -1336,6 +1336,35 @@ chi --remote studio --dir /Users/me/app -p "hi" # a new session there (--
|
|
|
1336
1336
|
has installed (`chi --remote studio sessions restart ab12`), this terminal
|
|
1337
1337
|
older than studio (`chi update` here).
|
|
1338
1338
|
|
|
1339
|
+
#### Through an SSH tunnel
|
|
1340
|
+
|
|
1341
|
+
When that machine's chi web is only reachable over SSH — behind a sign-in proxy
|
|
1342
|
+
(`chi --remote` through one isn't supported yet), or bound to 127.0.0.1 —
|
|
1343
|
+
forward its port and add it as a remote like any other:
|
|
1344
|
+
|
|
1345
|
+
```sh
|
|
1346
|
+
ssh -N -L 14567:127.0.0.1:4567 studio # the host's web.port, 4567 by default
|
|
1347
|
+
chi remote add work http://127.0.0.1:14567 --token-file work-token
|
|
1348
|
+
# work-token: the host's $XDG_STATE_HOME/samagotchi/web-token
|
|
1349
|
+
chi --remote work sessions list
|
|
1350
|
+
```
|
|
1351
|
+
|
|
1352
|
+
- Pick a local port other than 14567 when this machine runs its own chi web.
|
|
1353
|
+
- Forward only chi web's port, never a worker's: a session's Bridge is
|
|
1354
|
+
unauthenticated.
|
|
1355
|
+
- Without `web.public_url` there, a request that arrives through the tunnel
|
|
1356
|
+
looks local and needs no token, so any process here reaching the forwarded
|
|
1357
|
+
port acts as you there. With it set, every request needs the token, which
|
|
1358
|
+
`chi --remote` sends as Bearer.
|
|
1359
|
+
- `-L` binds 127.0.0.1 unless you write `-g` or `0.0.0.0:`: don't.
|
|
1360
|
+
- Attaching works through the tunnel too (`chi --remote work --attach ab12`),
|
|
1361
|
+
plain http, no proxy.
|
|
1362
|
+
|
|
1363
|
+
SSH can forward a Unix socket as well, which is how claude-peer's pairing makes
|
|
1364
|
+
a Claude session on this laptop reachable from chi on that machine
|
|
1365
|
+
(`pair --inbox-socket <path>`): see [plugins.md](plugins.md), "chi on another
|
|
1366
|
+
machine".
|
|
1367
|
+
|
|
1339
1368
|
How it works inside (`SessionAccess`, chi web's routes, where each check runs):
|
|
1340
1369
|
[internals/remote-sessions.md](internals/remote-sessions.md).
|
|
1341
1370
|
|
data/docs/configuration.md
CHANGED
|
@@ -1659,6 +1659,8 @@ What changes once `web.public_url` is set:
|
|
|
1659
1659
|
`X-Forwarded-For` or `Forwarded` (403 `proxied`). That is a heuristic, not a lock: a forward that adds no such header
|
|
1660
1660
|
(nginx's `proxy_pass` with its defaults, a plain TCP forward) still reaches a worker, as the owner.
|
|
1661
1661
|
- `chi --remote` to a chi web behind a sign-in proxy isn't supported yet.
|
|
1662
|
+
SSH to that machine works instead: forward its port and add it as a remote
|
|
1663
|
+
([Through an SSH tunnel](cli.md#through-an-ssh-tunnel)).
|
|
1662
1664
|
|
|
1663
1665
|
> **Warning.** Until Bridges get a secret of their own (planned), don't run chi web behind a proxy or tunnel that can
|
|
1664
1666
|
> reach any local port, such as a pod forwarding every `https://<port>.<pod>…`, unless it adds `X-Forwarded-For` or
|
data/docs/plugins.md
CHANGED
|
@@ -2249,6 +2249,26 @@ Claude pairs; without one the bundle costs one tool declaration.
|
|
|
2249
2249
|
them (or ask it to run `chi --remote studio send --wait <id>`). A session
|
|
2250
2250
|
that already has a `claude-inbox` it can't reach:
|
|
2251
2251
|
`chi --remote studio context rm claude-inbox <id>`.
|
|
2252
|
+
**Two ways to make it two-way over SSH.** SSH can forward a Unix socket, so
|
|
2253
|
+
the inbox leg works too. On the laptop:
|
|
2254
|
+
|
|
2255
|
+
```sh
|
|
2256
|
+
ssh studio rm -f /tmp/claude-peer-ab12.sock
|
|
2257
|
+
ssh -N -o ExitOnForwardFailure=yes -R /tmp/claude-peer-ab12.sock:"$CLAUDE_CODE_MESSAGING_SOCKET" studio
|
|
2258
|
+
```
|
|
2259
|
+
|
|
2260
|
+
the second running in the background while chi may send (the `rm -f` first:
|
|
2261
|
+
a remote forward's stale socket is replaced only when the **server's** sshd
|
|
2262
|
+
has `StreamLocalBindUnlink yes`). Then
|
|
2263
|
+
`CHI_REMOTE=studio sh <bundle>/scripts/pair --inbox-socket /tmp/claude-peer-ab12.sock ab12`
|
|
2264
|
+
attaches both sources, with `claude-inbox`'s hint that path on the Studio. A
|
|
2265
|
+
re-pair this way replaces an outbox-only pairing's `claude-outbox` and its
|
|
2266
|
+
why. Claude's socket changes when that Claude session restarts: stop the ssh,
|
|
2267
|
+
run both lines, pair again. A path chi quotes (a `payload:` file, a diff to
|
|
2268
|
+
check) is on the Studio, not the laptop. Whoever can write to that socket on
|
|
2269
|
+
the remote machine can send into this Claude session (sshd makes it the
|
|
2270
|
+
user's, mode 0600 by default): fine on your own machine or pod, not a shared
|
|
2271
|
+
host. Claude's own skill has the same under "chi on another machine over SSH".
|
|
2252
2272
|
- **Asking first.** The tool has no `targets:`, so guardrails match it by name
|
|
2253
2273
|
only: to be asked before each send, add a rule ([Rules in
|
|
2254
2274
|
config.yml](guardrails.md#rules-in-configyml)):
|
|
@@ -2353,6 +2373,8 @@ skill install card) works the same.
|
|
|
2353
2373
|
<bundle>/scripts/pair <id>` (or `--remote NAME` in `CHI`) pairs through
|
|
2354
2374
|
the Studio's chi web, and only the outbox leg works: `codex_send` runs
|
|
2355
2375
|
`codex queue` on the machine chi runs on, where this Codex's thread isn't.
|
|
2376
|
+
Claude's `--inbox-socket` trick doesn't apply here: `codex-inbox`'s hint is a
|
|
2377
|
+
thread id, not a socket, so there is nothing to forward through SSH.
|
|
2356
2378
|
So `pair` attaches only `codex-outbox` and prints one line saying chi there
|
|
2357
2379
|
can't send to this Codex. Through a remote chi talks HTTP, not files, so
|
|
2358
2380
|
`writable_roots` doesn't matter; Codex's sandbox may block the network
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: claude-peer
|
|
3
|
-
version: 0.4.
|
|
3
|
+
version: 0.4.3
|
|
4
4
|
scope: system
|
|
5
5
|
description: "Pair this session with a Claude Code session you work with: the claude_send tool and /claude send it a part of the work (a plan step, a diff, a finding) to validate or as context, and Claude's answer comes back as the claude-outbox context; /claude install-skill installs Claude's chi-peer skill, which pairs"
|
|
6
6
|
trust_level: reviewed
|
|
@@ -12,8 +12,8 @@ plugin:
|
|
|
12
12
|
file: plugin.rb
|
|
13
13
|
sha256: sha256:50f427d3862ae9d0d15693b4d887c528162b96c0320cc663df89d59d830d4660
|
|
14
14
|
scripts:
|
|
15
|
-
pair: sha256:
|
|
16
|
-
chi-peer-SKILL.md: sha256:
|
|
15
|
+
pair: sha256:bd850e8091098e249ac5b9b04a95a4d8a0dd8501cf9d58639a47d4f3bce1d757
|
|
16
|
+
chi-peer-SKILL.md: sha256:b9366f8f4aee9c54d209368ce421eab7b971c03c75efab0415d1988fd40f9e60
|
|
17
17
|
# The plugin needs Samagotchi::Plugin::Peer and chi.peer_source (chi 0.67.0).
|
|
18
18
|
# An agreeing answer's closing wake (the skills say an OK wakes chi once)
|
|
19
19
|
# and the plugin's OUTBOX (Plugin::Peer's rename of REVIEW) need chi 0.70.0.
|
|
@@ -89,6 +89,54 @@ EOF
|
|
|
89
89
|
- Never answer a chi message with `chi send`: it counts as the user typing,
|
|
90
90
|
outside the round's limit. Use it only when the user asks you to.
|
|
91
91
|
|
|
92
|
+
## chi on another machine over SSH
|
|
93
|
+
|
|
94
|
+
When the chi session runs on a machine this Claude session reaches with SSH
|
|
95
|
+
(the user says so, or `CHI_REMOTE` or a remote URL is in play) and chi should
|
|
96
|
+
send here too, pair with `--inbox-socket`: the socket chi writes to is then one
|
|
97
|
+
on chi's machine, an `ssh -R` forward of this session's socket.
|
|
98
|
+
|
|
99
|
+
You need a chi remote for that machine first (`chi remote add <name> <url>`,
|
|
100
|
+
through an `ssh -L` tunnel if that is how you reach it — docs/cli.md "Through
|
|
101
|
+
an SSH tunnel"). Then, with the host and the chi session's first 8 chars:
|
|
102
|
+
|
|
103
|
+
```sh
|
|
104
|
+
ssh <host> rm -f /tmp/claude-peer-<id8>.sock
|
|
105
|
+
ssh -N -o ExitOnForwardFailure=yes -R /tmp/claude-peer-<id8>.sock:"$CLAUDE_CODE_MESSAGING_SOCKET" <host>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Run the second in the background: it must keep running while chi may send. If
|
|
109
|
+
ssh wants a password or 2FA, print both lines with the socket spelled out and
|
|
110
|
+
ask the user to run them in a terminal. The `rm -f` matters: a stale remote
|
|
111
|
+
socket is not replaced unless the **server's** sshd has `StreamLocalBindUnlink
|
|
112
|
+
yes` (the client's `-o StreamLocalBindUnlink` covers `-L` only). A server with
|
|
113
|
+
`AllowStreamLocalForwarding no` refuses the forward at start
|
|
114
|
+
(`ExitOnForwardFailure`): tell the user, there is no fallback.
|
|
115
|
+
|
|
116
|
+
Then pair through the remote:
|
|
117
|
+
|
|
118
|
+
```sh
|
|
119
|
+
CHI_REMOTE=<name> sh "__CHI_PEER_PAIR__" --inbox-socket /tmp/claude-peer-<id8>.sock <id>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
The socket must be visible to chi's process on that machine (chi runs as the
|
|
123
|
+
SSH user, in the same `/tmp`, not inside a separate container): if `/claude`
|
|
124
|
+
in chi shows the socket **missing** while ssh is running, that is why.
|
|
125
|
+
|
|
126
|
+
Replies are the same push, through the remote:
|
|
127
|
+
`CHI_REMOTE=<name> chi context push claude-outbox <id>`.
|
|
128
|
+
|
|
129
|
+
A path in a chi message — a `payload: <path>` file, a file or a diff to check —
|
|
130
|
+
is on `<host>`, not here: read it with `ssh <host> cat <path>` (or the repo
|
|
131
|
+
there). The `Read(...)` permission note for payload files does not apply.
|
|
132
|
+
|
|
133
|
+
After this Claude session restarts its socket changes: stop the old ssh, run
|
|
134
|
+
both lines again, pair again.
|
|
135
|
+
|
|
136
|
+
Security: whoever can write to that socket on the remote machine can send
|
|
137
|
+
prompts into this session (sshd makes it the user's, mode 0600 by default).
|
|
138
|
+
Fine on the user's own machine or pod, not on a shared host.
|
|
139
|
+
|
|
92
140
|
## Don't loop
|
|
93
141
|
|
|
94
142
|
Never reply to an acknowledgement, a thanks, or a message that only confirms
|
|
@@ -10,22 +10,45 @@
|
|
|
10
10
|
# only refreshes the socket: the push carries the new hint. CHI names the chi
|
|
11
11
|
# command (default: chi on the PATH). Through a remote (CHI_REMOTE, or
|
|
12
12
|
# --remote NAME in CHI) chi there can't reach this machine's socket: it
|
|
13
|
-
# attaches claude-outbox only, and says so.
|
|
13
|
+
# attaches claude-outbox only, and says so. With --inbox-socket PATH the hint
|
|
14
|
+
# is PATH instead, a socket on chi's machine made by forwarding this Claude's
|
|
15
|
+
# socket there with `ssh -R`, so chi can send here too (docs/plugins.md).
|
|
14
16
|
set -eu
|
|
15
17
|
|
|
16
18
|
usage() {
|
|
17
|
-
echo "usage: pair <chi session id or URL (http://127.0.0.1:4567/#/s/<id>)>" >&2
|
|
19
|
+
echo "usage: pair [--inbox-socket PATH] <chi session id or URL (http://127.0.0.1:4567/#/s/<id>)>" >&2
|
|
18
20
|
exit 2
|
|
19
21
|
}
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
# The id (or URL) and, optionally, the socket on chi's machine to send through.
|
|
24
|
+
inbox= target=
|
|
25
|
+
while [ $# -gt 0 ]; do
|
|
26
|
+
case "$1" in
|
|
27
|
+
--inbox-socket)
|
|
28
|
+
[ $# -ge 2 ] || usage
|
|
29
|
+
inbox=$2 shift 2
|
|
30
|
+
[ -n "$inbox" ] || usage
|
|
31
|
+
;;
|
|
32
|
+
--inbox-socket=*)
|
|
33
|
+
inbox=${1#--inbox-socket=} shift
|
|
34
|
+
[ -n "$inbox" ] || usage
|
|
35
|
+
;;
|
|
36
|
+
-h | --help) usage ;;
|
|
37
|
+
*)
|
|
38
|
+
[ -z "$target" ] || usage
|
|
39
|
+
target=$1 shift
|
|
40
|
+
;;
|
|
41
|
+
esac
|
|
42
|
+
done
|
|
43
|
+
[ -n "$target" ] || usage
|
|
44
|
+
|
|
45
|
+
# A relative path would be chi's cwd, not the forward's remote end: the
|
|
46
|
+
# plugin's check refuses it, so refuse it here with the reason.
|
|
47
|
+
case "$inbox" in
|
|
48
|
+
"") ;;
|
|
49
|
+
/*) ;;
|
|
50
|
+
*) echo "pair: --inbox-socket needs an absolute socket path on chi's machine (the ssh -R forward's remote end): $inbox" >&2
|
|
51
|
+
exit 2 ;;
|
|
29
52
|
esac
|
|
30
53
|
|
|
31
54
|
sock=${CLAUDE_CODE_MESSAGING_SOCKET:-}
|
|
@@ -33,6 +56,7 @@ if [ -z "$sock" ]; then
|
|
|
33
56
|
echo "pair: CLAUDE_CODE_MESSAGING_SOCKET isn't set: run this from a Claude Code session (2.1.224 or later)" >&2
|
|
34
57
|
exit 2
|
|
35
58
|
fi
|
|
59
|
+
|
|
36
60
|
chi=${CHI:-chi}
|
|
37
61
|
|
|
38
62
|
# The remote, as SessionAccess::Dispatch names it: a --remote NAME (or
|
|
@@ -52,6 +76,14 @@ for word in $chi; do
|
|
|
52
76
|
esac
|
|
53
77
|
done
|
|
54
78
|
|
|
79
|
+
case "$target" in
|
|
80
|
+
http://* | https://*)
|
|
81
|
+
id=$(printf '%s\n' "$target" | sed -n 's|.*/s/\([0-9A-Za-z-][0-9A-Za-z-]*\).*|\1|p')
|
|
82
|
+
[ -n "$id" ] || { echo "pair: no session id in $target (a chi web URL ends in #/s/<id>)" >&2; exit 2; }
|
|
83
|
+
;;
|
|
84
|
+
*) id=$target ;;
|
|
85
|
+
esac
|
|
86
|
+
|
|
55
87
|
# A JSON string: backslashes, quotes, tabs and newlines escaped.
|
|
56
88
|
json() {
|
|
57
89
|
printf '%s' "$1" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/ /\\t/g' |
|
|
@@ -70,26 +102,51 @@ attach() {
|
|
|
70
102
|
fi
|
|
71
103
|
}
|
|
72
104
|
|
|
73
|
-
|
|
105
|
+
# Without a socket chi can reach, only the outbox leg works.
|
|
106
|
+
if [ -n "$via" ] && [ -z "$inbox" ]; then
|
|
74
107
|
attach claude-outbox --why "Claude's answers to what you sent it (claude-peer); Claude runs on another machine: claude_send can't reach it" \
|
|
75
108
|
--hint "latest Claude reply"
|
|
76
109
|
ask=$chi
|
|
77
110
|
[ "$via" = chi ] || ask="CHI_REMOTE=$remote $chi"
|
|
78
111
|
printf '%s\n' "pair: chi is on $remote, so chi can't send to this Claude session (claude_send needs its socket on chi's machine): paired with chi $id, claude-outbox only. Answer chi with $ask context push claude-outbox $id; chi's replies reach you only when the user relays them (or asks you to run $ask send --wait $id)"
|
|
112
|
+
printf '%s\n' "pair: to let chi send here too, forward this Claude's socket to $remote with ssh -R and pair again with --inbox-socket (the chi-peer skill's \"chi on another machine over SSH\")"
|
|
79
113
|
$chi context ls "$id"
|
|
80
114
|
exit 0
|
|
81
115
|
fi
|
|
82
116
|
|
|
83
|
-
|
|
84
|
-
|
|
117
|
+
hint=${inbox:-$sock}
|
|
118
|
+
if [ -z "$inbox" ]; then
|
|
119
|
+
text="Claude Code peer inbox
|
|
85
120
|
socket: $sock
|
|
86
121
|
claude cwd: $PWD
|
|
87
122
|
paired: $(date '+%Y-%m-%d %H:%M')
|
|
88
123
|
Send to it with the claude_send tool (your skill_claude_peer memory); its answers come as the claude-outbox context."
|
|
89
|
-
|
|
90
|
-
|
|
124
|
+
summary="Claude Code paired from $PWD"
|
|
125
|
+
else
|
|
126
|
+
text="Claude Code peer inbox
|
|
127
|
+
socket: $inbox (on this machine: an ssh -R forward of Claude's socket $sock on Claude's machine)
|
|
128
|
+
claude cwd: $PWD
|
|
129
|
+
paired: $(date '+%Y-%m-%d %H:%M')
|
|
130
|
+
Send to it with the claude_send tool (your skill_claude_peer memory); its answers come as the claude-outbox context.
|
|
131
|
+
If claude_send says the Claude session is gone, the ssh tunnel may be down: tell the user to restart it and pair again."
|
|
132
|
+
summary="Claude Code paired from $PWD over ssh"
|
|
133
|
+
fi
|
|
134
|
+
|
|
135
|
+
attach claude-inbox --why "the Claude Code session paired with you: send it parts with claude_send" --hint "$hint"
|
|
136
|
+
printf '{"text":%s,"hint":%s,"summary":%s}\n' "$(json "$text")" "$(json "$hint")" "$(json "$summary")" \
|
|
137
|
+
| $chi context push claude-inbox "$id" >/dev/null
|
|
91
138
|
|
|
139
|
+
# An outbox attached by an earlier outbox-only pairing carries the why that
|
|
140
|
+
# says claude_send can't reach Claude; context add never updates an existing
|
|
141
|
+
# source, so replace it (Claude's last answer goes with it).
|
|
142
|
+
if $chi context show claude-outbox --json "$id" 2>/dev/null | grep -q "can't reach it"; then
|
|
143
|
+
$chi context rm claude-outbox "$id" >/dev/null
|
|
144
|
+
fi
|
|
92
145
|
attach claude-outbox --why "Claude's answers to what you sent it (claude-peer)" --hint "latest Claude reply"
|
|
93
146
|
|
|
94
|
-
|
|
147
|
+
if [ -z "$inbox" ]; then
|
|
148
|
+
echo "paired with chi $id (socket $sock)"
|
|
149
|
+
else
|
|
150
|
+
echo "paired with chi $id (socket $inbox on chi's machine, forwarded from $sock)"
|
|
151
|
+
fi
|
|
95
152
|
$chi context ls "$id"
|
data/lib/samagotchi/version.rb
CHANGED
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><rect x="1" y="1" width="30" height="30" rx="7.5" fill="#22262f"/><g fill="none" stroke="#0a84ff" stroke-width="3.2" stroke-linecap="round" stroke-linejoin="round"><path d="M7.8 9.6c2.3-1.3 4-.7 5.2 1.4l6 10.1c1.2 2.1 2.9 2.7 5.2 1.4"/><path d="M22.6 9.2 9.4 22.8"/></g></svg>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*{box-sizing:border-box;margin:0;padding:0}
|
|
18
18
|
/* No iOS text autosizing: it grows text in a box sized for the text as written (it clipped the session cards). */
|
|
19
19
|
html{-webkit-text-size-adjust:100%;text-size-adjust:100%}
|
|
20
|
-
body{font-family: ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background:radial-gradient(1100px 700px at 8% 0%,color-mix(in srgb,var(--accent) 13%,transparent),transparent 70%),
|
|
20
|
+
body{font-family: ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background:radial-gradient(1100px 700px at 8% 0%,color-mix(in srgb,var(--accent) 13%,transparent),transparent 70%),var(--bg);background-attachment:fixed;color:var(--text);height:100vh;display:flex;flex-direction:column}
|
|
21
21
|
/* Glass: the composer card, the strip cards, the all-sessions cards and the question cards (by selector, so app.js is untouched). */
|
|
22
22
|
#dock,.turn-stage,.dock-card,#topStrip .card,#allList .card,.bubble.question,.bubble.plugin-card{background:var(--glass-bg);-webkit-backdrop-filter:blur(18px) saturate(1.35);backdrop-filter:blur(18px) saturate(1.35);border:1px solid var(--glass-border);box-shadow:inset 0 1px 0 var(--glass-highlight),var(--glass-shadow)}
|
|
23
23
|
#topStrip .card:hover,#allList .card:hover{background:color-mix(in srgb,var(--bg-hover) 75%,transparent);border-color:var(--card-hover-border)}
|
|
@@ -1067,7 +1067,11 @@ button.ws-row:hover:not(:disabled){filter:none;background:var(--bg-hover)}
|
|
|
1067
1067
|
@media (prefers-reduced-motion:reduce){.turn-stage.enter,.ts-arrive,.ts-headline.fresh,.ts-tick.running,.ts-mark,.turn-work:not(.done) .activity-status.running::before{animation:none}.turn-stage.leaving,#center.reserve-easing #history{transition:none}}
|
|
1068
1068
|
#infoBar{display:flex;padding:8px 14px 10px;border-top:1px solid var(--glass-border);background:transparent;border-radius:0 0 16px 16px;color:var(--text-2);gap:10px;align-items:flex-start;flex-wrap:wrap;flex-shrink:0;transition:opacity 280ms ease}
|
|
1069
1069
|
#infoBar.visible{display:flex}
|
|
1070
|
-
|
|
1070
|
+
/* The meta row keeps its room: with a plain flex:1 the bar's own buttons (continue, archive, stop session, delete)
|
|
1071
|
+
shrink it to a narrow column in a small window and its items wrap into five lines. With a 640px basis they share
|
|
1072
|
+
the line while they fit; when they don't, the buttons wrap to a line of their own (the bar already wraps) and the
|
|
1073
|
+
meta keeps the width. */
|
|
1074
|
+
#infoBar .info{flex:1 1 640px;min-width:0;font-size:13px;line-height:1.4;word-break:break-word;display:flex;flex-direction:column;gap:2px}
|
|
1071
1075
|
#infoBar .meta{font-size:11px;display:flex;gap:8px;flex-wrap:wrap;align-items:center}
|
|
1072
1076
|
#infoBar .meta .id{font-family:ui-monospace,monospace;font-weight:700;font-size:12px;color:var(--accent)}
|
|
1073
1077
|
#infoBar .meta .copy-attach{padding:2px 8px;border-radius:6px;font-size:11px;font-weight:600;background:var(--bg-raised);color:var(--text-2);border:1px solid var(--border-strong)}
|
|
@@ -1082,6 +1086,12 @@ button.ws-row:hover:not(:disabled){filter:none;background:var(--bg-hover)}
|
|
|
1082
1086
|
#infoBar .meta .dir{font-family:ui-monospace,monospace;font-size:11px;color:var(--text-muted);max-width:48ch;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;direction:rtl;text-align:left}
|
|
1083
1087
|
/* The footer sits on the card's glass: its chips are tinted, not solid, so the glass reads through them. */
|
|
1084
1088
|
#infoBar .meta .model{font-size:11px;padding:2px 6px;border-radius:6px;background:color-mix(in srgb,var(--bg-hover) 55%,transparent);color:var(--text-3)}
|
|
1089
|
+
/* Where the meta row wraps (above the phone's one scrolling line) the two long items give way so it stays two lines: the
|
|
1090
|
+
folder takes at most a third of the row and a chip at most 30%, cut with "…", their full text in the title. */
|
|
1091
|
+
@media(min-width:601px){
|
|
1092
|
+
#infoBar .meta .dir{max-width:min(48ch,32%)}
|
|
1093
|
+
#infoBar .meta .model{max-width:min(40ch,30%);min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
1094
|
+
}
|
|
1085
1095
|
/* The plain chips (spans, links) and the status take the button chips' 1px border, transparent and outside their tint, so every chip is one height: a chip wrapping onto a row of plain ones doesn't grow it. */
|
|
1086
1096
|
#infoBar .meta :is(span,a).model,#infoBar .meta .status{border:1px solid transparent;background-clip:padding-box}
|
|
1087
1097
|
/* The chips a running turn rewrites (the session clock each second, the last generation's speed, ctx): tabular digits in a reserved width, so a tick ("9.5s" → "10s" → "1m 00s") or a new number doesn't widen the line and wrap a chip onto a new row. The speed and the clock show from the session's start, a muted placeholder until there is a number. */
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"scope": "/",
|
|
6
6
|
"display": "standalone",
|
|
7
7
|
"background_color": "#0b0d11",
|
|
8
|
-
"theme_color": "#
|
|
8
|
+
"theme_color": "#5aa9ff",
|
|
9
9
|
"icons": [
|
|
10
10
|
{ "src": "/icons/chi-192.png", "sizes": "192x192", "type": "image/png" },
|
|
11
11
|
{ "src": "/icons/chi-512.png", "sizes": "512x512", "type": "image/png" }
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/* The web UI's colour tokens, shared by the owner's page (index.html) and the participant page (participant.html): the dark :root (the default) and the light set under prefers-color-scheme: light. Everything else reads them through var(). */
|
|
2
|
-
:root{color-scheme:dark;--bg:#0b0d11;--bg-panel:#151821;--bg-inset:#0f1115;--bg-raised:#22262f;--bg-hover:#1b1f27;--border:#1f232b;--border-strong:#2d333f;--text:#e6e8eb;--text-bright:#f0f3f6;--text-2:#c9d1d9;--text-3:#9aa4b2;--text-muted:#8b949e;--text-faint:#6e7681;--accent:#
|
|
2
|
+
:root{color-scheme:dark;--bg:#0b0d11;--bg-panel:#151821;--bg-inset:#0f1115;--bg-raised:#22262f;--bg-hover:#1b1f27;--border:#1f232b;--border-strong:#2d333f;--text:#e6e8eb;--text-bright:#f0f3f6;--text-2:#c9d1d9;--text-3:#9aa4b2;--text-muted:#8b949e;--text-faint:#6e7681;--accent:#5aa9ff;--accent-strong:#0071e3;--accent-bg:#0f2340;--accent-ring:rgba(90,169,255,.18);--primary:#0071e3;--ok:#3fb950;--ok-text:#7ee787;--ok-bg:#1a2e1a;--warn:#d29922;--warn-text:#e3b341;--warn-bright:#f2cc60;--warn-bg:#2b2108;--warn-border:#6b5416;--danger:#f85149;--danger-bg:#da3633;--danger-text:#ff7b72;--danger-bg-dim:#3d1f1f;--think:#8957e5;--think-text:#d2a8ff;--accent-border:#1a3458;--pick-border:#79c0ff;--accent-tint:color-mix(in srgb,var(--accent) 7%,transparent);--narr:color-mix(in srgb,var(--accent) 38%,var(--text-muted));
|
|
3
3
|
--glass-bg:color-mix(in srgb,var(--bg-panel) 70%,transparent);--glass-border:rgba(255,255,255,.08);--glass-highlight:rgba(255,255,255,.05);--glass-shadow:0 8px 30px rgba(0,0,0,.35);
|
|
4
4
|
--diff-add-bg:rgba(63,185,80,.14);--diff-add-text:#aff5b4;--diff-del-bg:rgba(248,81,73,.14);--diff-del-text:#ffc1bc;
|
|
5
5
|
--code-text:#c9d1d9;--code-keyword:#ff7b72;--code-string:#a5d6ff;--code-comment:#8b949e;--code-constant:#79c0ff;--code-func:#d2a8ff;--code-type:#ffa657;
|
|
6
6
|
--card-hover-border:rgba(255,255,255,.14);--on-solid:#fff;--on-warn:#fff;--text-hover:#fff;--badge-bg:rgba(255,255,255,.08);--badge-ring:rgba(255,255,255,.18);--shadow-strong:rgba(0,0,0,.5);--backdrop:rgba(0,0,0,.85);--toast-shadow:0 6px 24px rgba(0,0,0,.25);--ws-stale-opacity:.4;--ws-rule:var(--border-strong);--ws-muted:var(--text-3);--ws-faint:var(--text-muted);--ws-act-border:#444c56;--author-1:#79c0ff;--author-2:#d2a8ff;--author-3:#7ee787;--author-4:#ffa657;--author-5:#ff7b72;--author-6:#f2cc60;--author-owner:var(--text-3);--time-gap:var(--text-faint)}
|
|
7
7
|
/* Light palette: follows the system setting. :not([data-theme="dark"]) leaves room for a later in-page toggle (data-theme on <html>); there is none yet. Each palette sets color-scheme, so native radios, inputs and scrollbars follow it. */
|
|
8
|
-
@media (prefers-color-scheme:light){:root:not([data-theme="dark"]){color-scheme:light;--bg:#f5f6f8;--bg-panel:#ffffff;--bg-inset:#f1f3f6;--bg-raised:#e8ebf0;--bg-hover:#eceff4;--border:#dde1e7;--border-strong:#c3c9d2;--text:#1f2328;--text-bright:#0d1117;--text-2:#2f363d;--text-3:#475160;--text-muted:#57606a;--text-faint:#636c76;--accent:#
|
|
8
|
+
@media (prefers-color-scheme:light){:root:not([data-theme="dark"]){color-scheme:light;--bg:#f5f6f8;--bg-panel:#ffffff;--bg-inset:#f1f3f6;--bg-raised:#e8ebf0;--bg-hover:#eceff4;--border:#dde1e7;--border-strong:#c3c9d2;--text:#1f2328;--text-bright:#0d1117;--text-2:#2f363d;--text-3:#475160;--text-muted:#57606a;--text-faint:#636c76;--accent:#0066cc;--accent-strong:#0058b0;--accent-bg:#e3f0ff;--accent-ring:rgba(0,102,204,.2);--primary:#0071e3;--ok:#1a7f37;--ok-text:#116329;--ok-bg:#dafbe1;--warn:#9a6700;--warn-text:#7d4e00;--warn-bright:#875c00;--warn-bg:#fff6cc;--warn-border:#d4a72c;--danger:#cf222e;--danger-bg:#cf222e;--danger-text:#a40e26;--danger-bg-dim:#ffebe9;--think:#8250df;--think-text:#6639ba;--accent-border:#b3d4f7;--pick-border:#0969da;
|
|
9
9
|
--glass-border:rgba(31,35,40,.10);--glass-highlight:rgba(255,255,255,.7);--glass-shadow:0 8px 30px rgba(31,35,40,.10);
|
|
10
10
|
--diff-add-bg:rgba(26,127,55,.12);--diff-add-text:#116329;--diff-del-bg:rgba(207,34,46,.10);--diff-del-text:#82071e;
|
|
11
11
|
--code-text:#1f2328;--code-keyword:#cf222e;--code-string:#0a3069;--code-comment:#57606a;--code-constant:#0550ae;--code-func:#8250df;--code-type:#953800;
|