@dmsdc-ai/aterm-darwin-arm64 0.1.39 → 0.1.41
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.
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# aterm — CLI for aterm internal workspace communication
|
|
3
|
+
# Sends NDJSON over $ATERM_IPC_SOCKET. Falls back to telepty outside aterm.
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
|
|
6
|
+
ATERM_IPC_SOCKET="${ATERM_IPC_SOCKET:-}"
|
|
7
|
+
|
|
8
|
+
# State directory for task board and lessons
|
|
9
|
+
STATE_DIR="${PWD}/state"
|
|
10
|
+
|
|
11
|
+
tasks_file() { echo "${STATE_DIR}/task-queue.json"; }
|
|
12
|
+
lessons_file() { echo "${STATE_DIR}/lessons.json"; }
|
|
13
|
+
|
|
14
|
+
ensure_state_dir() { mkdir -p "$STATE_DIR"; }
|
|
15
|
+
|
|
16
|
+
ensure_tasks_file() {
|
|
17
|
+
ensure_state_dir
|
|
18
|
+
local f; f="$(tasks_file)"
|
|
19
|
+
[ -f "$f" ] || echo '{"tasks":[],"completed":[]}' > "$f"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
ensure_lessons_file() {
|
|
23
|
+
ensure_state_dir
|
|
24
|
+
local f; f="$(lessons_file)"
|
|
25
|
+
[ -f "$f" ] || echo '{"invariants":[],"failed":[]}' > "$f"
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
aterm_ipc() {
|
|
29
|
+
python3 -c '
|
|
30
|
+
import socket, sys, json
|
|
31
|
+
|
|
32
|
+
sock_path = sys.argv[1]
|
|
33
|
+
action = sys.argv[2]
|
|
34
|
+
args = sys.argv[3:]
|
|
35
|
+
|
|
36
|
+
payloads = {
|
|
37
|
+
"list": lambda: {"action": "ListWorkspaces"},
|
|
38
|
+
"inject": lambda: {"action": "Inject", "workspace": args[0],
|
|
39
|
+
"text": " ".join(args[1:]),
|
|
40
|
+
"from": __import__("os").environ.get("ATERM_WORKSPACE_NAME")},
|
|
41
|
+
"status": lambda: {"action": "WorkspaceStatus", "workspace": args[0]},
|
|
42
|
+
"focus": lambda: {"action": "FocusWorkspace", "workspace": args[0]},
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
payload = json.dumps(payloads[action]()) + "\n"
|
|
46
|
+
|
|
47
|
+
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
48
|
+
try:
|
|
49
|
+
sock.settimeout(5)
|
|
50
|
+
sock.connect(sock_path)
|
|
51
|
+
sock.sendall(payload.encode())
|
|
52
|
+
sock.shutdown(socket.SHUT_WR)
|
|
53
|
+
data = b""
|
|
54
|
+
while True:
|
|
55
|
+
chunk = sock.recv(4096)
|
|
56
|
+
if not chunk:
|
|
57
|
+
break
|
|
58
|
+
data += chunk
|
|
59
|
+
if b"\n" in data:
|
|
60
|
+
break
|
|
61
|
+
resp = json.loads(data.decode().strip().split("\n")[0])
|
|
62
|
+
|
|
63
|
+
if resp.get("status") == "Error":
|
|
64
|
+
print(json.dumps({"error": resp["message"]}), file=sys.stderr)
|
|
65
|
+
sys.exit(1)
|
|
66
|
+
elif action == "list":
|
|
67
|
+
print(json.dumps({"sessions": resp.get("data", [])}))
|
|
68
|
+
elif action == "status":
|
|
69
|
+
print(json.dumps(resp.get("data", {})))
|
|
70
|
+
else:
|
|
71
|
+
print(json.dumps({"status": "ok"}))
|
|
72
|
+
except Exception as e:
|
|
73
|
+
print(json.dumps({"error": str(e)}), file=sys.stderr)
|
|
74
|
+
sys.exit(1)
|
|
75
|
+
finally:
|
|
76
|
+
sock.close()
|
|
77
|
+
' "$ATERM_IPC_SOCKET" "$@"
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
case "${1:-help}" in
|
|
81
|
+
list)
|
|
82
|
+
if [[ -z "$ATERM_IPC_SOCKET" ]]; then exec telepty list "${@:2}"; fi
|
|
83
|
+
aterm_ipc list ;;
|
|
84
|
+
inject)
|
|
85
|
+
if [[ -z "$ATERM_IPC_SOCKET" ]]; then exec telepty inject "${@:2}"; fi
|
|
86
|
+
[[ $# -lt 3 ]] && { echo '{"error":"usage: aterm inject <workspace> <text>"}' >&2; exit 1; }
|
|
87
|
+
aterm_ipc inject "${@:2}" ;;
|
|
88
|
+
status)
|
|
89
|
+
if [[ -z "$ATERM_IPC_SOCKET" ]]; then exec telepty status "${@:2}"; fi
|
|
90
|
+
[[ $# -lt 2 ]] && { echo '{"error":"usage: aterm status <workspace>"}' >&2; exit 1; }
|
|
91
|
+
aterm_ipc status "$2" ;;
|
|
92
|
+
focus)
|
|
93
|
+
[[ -z "$ATERM_IPC_SOCKET" ]] && { echo '{"error":"focus requires aterm (ATERM_IPC_SOCKET not set)"}' >&2; exit 1; }
|
|
94
|
+
[[ $# -lt 2 ]] && { echo '{"error":"usage: aterm focus <workspace>"}' >&2; exit 1; }
|
|
95
|
+
aterm_ipc focus "$2" ;;
|
|
96
|
+
tasks)
|
|
97
|
+
ensure_tasks_file
|
|
98
|
+
case "${2:-list}" in
|
|
99
|
+
list)
|
|
100
|
+
python3 -c '
|
|
101
|
+
import json, sys
|
|
102
|
+
with open(sys.argv[1]) as f: data = json.load(f)
|
|
103
|
+
if not data.get("tasks"):
|
|
104
|
+
print("No pending tasks.")
|
|
105
|
+
sys.exit(0)
|
|
106
|
+
for i, t in enumerate(data["tasks"]):
|
|
107
|
+
tid = t.get("id", i)
|
|
108
|
+
desc = t.get("description", t) if isinstance(t, dict) else t
|
|
109
|
+
print(f" [{tid}] {desc}")
|
|
110
|
+
' "$(tasks_file)" ;;
|
|
111
|
+
add)
|
|
112
|
+
[[ $# -lt 3 ]] && { echo '{"error":"usage: aterm tasks add <description>"}' >&2; exit 1; }
|
|
113
|
+
python3 -c '
|
|
114
|
+
import json, sys, time
|
|
115
|
+
f = sys.argv[1]; desc = " ".join(sys.argv[2:])
|
|
116
|
+
with open(f) as fh: data = json.load(fh)
|
|
117
|
+
tid = int(time.time() * 1000) % 100000
|
|
118
|
+
data["tasks"].append({"id": tid, "description": desc})
|
|
119
|
+
with open(f, "w") as fh: json.dump(data, fh, indent=2, ensure_ascii=False); fh.write("\n")
|
|
120
|
+
print(json.dumps({"status":"ok","id": tid}))
|
|
121
|
+
' "$(tasks_file)" "${@:3}" ;;
|
|
122
|
+
done)
|
|
123
|
+
[[ $# -lt 3 ]] && { echo '{"error":"usage: aterm tasks done <id>"}' >&2; exit 1; }
|
|
124
|
+
python3 -c '
|
|
125
|
+
import json, sys
|
|
126
|
+
f = sys.argv[1]; target = int(sys.argv[2])
|
|
127
|
+
with open(f) as fh: data = json.load(fh)
|
|
128
|
+
found = None
|
|
129
|
+
for i, t in enumerate(data["tasks"]):
|
|
130
|
+
tid = t.get("id", i) if isinstance(t, dict) else i
|
|
131
|
+
if tid == target:
|
|
132
|
+
found = data["tasks"].pop(i)
|
|
133
|
+
break
|
|
134
|
+
if not found:
|
|
135
|
+
print(json.dumps({"error": f"task {target} not found"}), file=sys.stderr); sys.exit(1)
|
|
136
|
+
data.setdefault("completed", []).append(found)
|
|
137
|
+
with open(f, "w") as fh: json.dump(data, fh, indent=2, ensure_ascii=False); fh.write("\n")
|
|
138
|
+
print(json.dumps({"status":"ok","id": target}))
|
|
139
|
+
' "$(tasks_file)" "$3" ;;
|
|
140
|
+
*) echo '{"error":"usage: aterm tasks [list|add|done]"}' >&2; exit 1 ;;
|
|
141
|
+
esac ;;
|
|
142
|
+
lessons)
|
|
143
|
+
ensure_lessons_file
|
|
144
|
+
case "${2:-list}" in
|
|
145
|
+
list)
|
|
146
|
+
python3 -c '
|
|
147
|
+
import json, sys
|
|
148
|
+
with open(sys.argv[1]) as f: data = json.load(f)
|
|
149
|
+
inv = data.get("invariants", [])
|
|
150
|
+
fail = data.get("failed", [])
|
|
151
|
+
if not inv and not fail:
|
|
152
|
+
print("No lessons recorded.")
|
|
153
|
+
sys.exit(0)
|
|
154
|
+
if inv:
|
|
155
|
+
print("Invariants:")
|
|
156
|
+
for l in inv: print(f" - {l}")
|
|
157
|
+
if fail:
|
|
158
|
+
print("Failed patterns:")
|
|
159
|
+
for l in fail: print(f" - {l}")
|
|
160
|
+
' "$(lessons_file)" ;;
|
|
161
|
+
add)
|
|
162
|
+
[[ $# -lt 3 ]] && { echo '{"error":"usage: aterm lessons add <lesson> [--type invariant|failed]"}' >&2; exit 1; }
|
|
163
|
+
python3 -c '
|
|
164
|
+
import json, sys
|
|
165
|
+
f = sys.argv[1]; lesson = sys.argv[2]
|
|
166
|
+
ltype = "invariants"
|
|
167
|
+
if "--type" in sys.argv:
|
|
168
|
+
idx = sys.argv.index("--type")
|
|
169
|
+
if idx + 1 < len(sys.argv) and sys.argv[idx+1] == "failed":
|
|
170
|
+
ltype = "failed"
|
|
171
|
+
with open(f) as fh: data = json.load(fh)
|
|
172
|
+
data.setdefault(ltype, []).append(lesson)
|
|
173
|
+
with open(f, "w") as fh: json.dump(data, fh, indent=2, ensure_ascii=False); fh.write("\n")
|
|
174
|
+
print(json.dumps({"status":"ok","type": ltype}))
|
|
175
|
+
' "$(lessons_file)" "${@:3}" ;;
|
|
176
|
+
*) echo '{"error":"usage: aterm lessons [list|add]"}' >&2; exit 1 ;;
|
|
177
|
+
esac ;;
|
|
178
|
+
help|--help|-h)
|
|
179
|
+
cat <<'HELP'
|
|
180
|
+
# aterm — AI-native terminal session communication
|
|
181
|
+
|
|
182
|
+
## Commands
|
|
183
|
+
|
|
184
|
+
| Command | Description |
|
|
185
|
+
|---------|-------------|
|
|
186
|
+
| `aterm list` | List all workspaces (JSON) |
|
|
187
|
+
| `aterm inject <workspace> <text>` | Send text to a workspace |
|
|
188
|
+
| `aterm status <workspace>` | Check workspace status |
|
|
189
|
+
| `aterm focus <workspace>` | Focus a workspace tab |
|
|
190
|
+
| `aterm tasks` | List pending tasks |
|
|
191
|
+
| `aterm tasks add '<description>'` | Add a new task |
|
|
192
|
+
| `aterm tasks done <id>` | Mark task as completed |
|
|
193
|
+
| `aterm lessons` | List recorded lessons |
|
|
194
|
+
| `aterm lessons add '<lesson>'` | Add a lesson (invariant) |
|
|
195
|
+
| `aterm lessons add '<lesson>' --type failed` | Add a failed pattern |
|
|
196
|
+
| `aterm help` | Show this help |
|
|
197
|
+
|
|
198
|
+
## Natural Language → Command Mapping
|
|
199
|
+
|
|
200
|
+
### Internal sessions (same aterm, $ATERM_IPC_SOCKET set)
|
|
201
|
+
| Natural language | Command |
|
|
202
|
+
|-----------------|---------|
|
|
203
|
+
| 'list sessions' / '세션 목록 보여줘' | `aterm list` |
|
|
204
|
+
| 'send build to ghostty' / 'ghostty에 빌드 실행해줘' | `aterm inject ghostty 'make build'` |
|
|
205
|
+
| 'check cmux status' / 'cmux 세션 상태 확인해줘' | `aterm status cmux` |
|
|
206
|
+
| 'show tasks' / '태스크 목록 보여줘' | `aterm tasks` |
|
|
207
|
+
| 'add task: implement API' / '태스크 추가해줘: API 구현' | `aterm tasks add 'API 구현'` |
|
|
208
|
+
| 'task 42 done' / '태스크 42 완료' | `aterm tasks done 42` |
|
|
209
|
+
| 'show lessons' / '레슨 보여줘' | `aterm lessons` |
|
|
210
|
+
| 'add lesson: this pattern failed' / '레슨 추가' | `aterm lessons add 'this pattern failed'` |
|
|
211
|
+
|
|
212
|
+
### External sessions (other terminal/machine, $ATERM_IPC_SOCKET unset)
|
|
213
|
+
| Natural language | Command |
|
|
214
|
+
|-----------------|---------|
|
|
215
|
+
| 'list external sessions' / '외부 세션 목록' | `telepty list` |
|
|
216
|
+
| 'message deliberation session' | `telepty inject aigentry-deliberation-claude 'message'` |
|
|
217
|
+
|
|
218
|
+
## Detection Rules
|
|
219
|
+
- `$ATERM_IPC_SOCKET` set → inside aterm. Use `aterm` commands.
|
|
220
|
+
- `$ATERM_IPC_SOCKET` unset → outside aterm. Use `telepty` commands.
|
|
221
|
+
- `aterm` falls back to `telepty` automatically for list/inject/status.
|
|
222
|
+
HELP
|
|
223
|
+
;;
|
|
224
|
+
*) echo "{\"error\":\"unknown command: $1\"}" >&2; exit 1 ;;
|
|
225
|
+
esac
|
|
@@ -3,17 +3,29 @@
|
|
|
3
3
|
<plist version="1.0">
|
|
4
4
|
<dict>
|
|
5
5
|
<key>files</key>
|
|
6
|
-
<dict
|
|
6
|
+
<dict>
|
|
7
|
+
<key>Resources/bin/aterm</key>
|
|
8
|
+
<data>
|
|
9
|
+
gFvuG9DaXYDL7UTWZL/Tq5PcKnc=
|
|
10
|
+
</data>
|
|
11
|
+
</dict>
|
|
7
12
|
<key>files2</key>
|
|
8
13
|
<dict>
|
|
9
14
|
<key>Frameworks/libaterm_core.dylib</key>
|
|
10
15
|
<dict>
|
|
11
16
|
<key>cdhash</key>
|
|
12
17
|
<data>
|
|
13
|
-
|
|
18
|
+
8gJg6YBgIxIudeTA+itvRdqpKhk=
|
|
14
19
|
</data>
|
|
15
20
|
<key>requirement</key>
|
|
16
|
-
<string>cdhash H"
|
|
21
|
+
<string>cdhash H"f20260e9806023122e75e4c0fa2b6f45daa92a19"</string>
|
|
22
|
+
</dict>
|
|
23
|
+
<key>Resources/bin/aterm</key>
|
|
24
|
+
<dict>
|
|
25
|
+
<key>hash2</key>
|
|
26
|
+
<data>
|
|
27
|
+
MK+VFroryYcLv27zSIhkens5mXnx7gSJjhf90/iwmdQ=
|
|
28
|
+
</data>
|
|
17
29
|
</dict>
|
|
18
30
|
</dict>
|
|
19
31
|
<key>rules</key>
|