@link-assistant/hive-mind 1.78.12 → 2.0.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.
- package/CHANGELOG.md +14 -0
- package/README.hi.md +17 -17
- package/README.md +17 -17
- package/README.ru.md +17 -17
- package/README.zh.md +17 -17
- package/package.json +2 -2
- package/src/cleanup.lib.mjs +60 -4
- package/src/cleanup.mjs +10 -11
- package/src/cleanup.os.lib.mjs +8 -2
- package/src/confirmation.lib.mjs +90 -0
- package/src/github-merge.lib.mjs +49 -1
- package/src/github-terminal-state.lib.mjs +266 -0
- package/src/hive.mjs +2 -7
- package/src/solve.auto-merge-helpers.lib.mjs +16 -0
- package/src/solve.auto-merge.lib.mjs +58 -11
- package/src/solve.watch.lib.mjs +25 -1
- package/src/telegram-bot.mjs +30 -23
- package/src/telegram-merge-queue.lib.mjs +16 -0
- package/src/use-m-bootstrap.lib.mjs +37 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @link-assistant/hive-mind
|
|
2
2
|
|
|
3
|
+
## 2.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- fd84e85: Rename the cleanup executable to `hive-cleanup` and harden destructive confirmation parsing against hidden terminal control input.
|
|
8
|
+
|
|
9
|
+
## 1.78.13
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- a8035e9: Fail fast when watched GitHub repositories, issues, pull requests, or branches are deleted, closed, or no longer accessible instead of retrying them as unknown CI states.
|
|
14
|
+
|
|
15
|
+
Also fall back to a pinned working `use-m` bootstrap when the upstream latest unpkg entry is missing, so local and CI test startup remains stable.
|
|
16
|
+
|
|
3
17
|
## 1.78.12
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
package/README.hi.md
CHANGED
|
@@ -735,7 +735,7 @@ solve https://github.com/owner/repo/issues/123 --resume 657e6db1-6eb3-4a8d
|
|
|
735
735
|
|
|
736
736
|
### डिस्क क्लीनअप
|
|
737
737
|
|
|
738
|
-
`cleanup` पुरानी hive-mind अस्थायी डायरेक्टरी/फ़ाइलों (जैसे प्रति-कार्य क्लोन
|
|
738
|
+
`hive-cleanup` पुरानी hive-mind अस्थायी डायरेक्टरी/फ़ाइलों (जैसे प्रति-कार्य क्लोन
|
|
739
739
|
`/tmp/gh-issue-solver-*`, MCP कॉन्फ़िग फ़ाइलें, लॉग डाउनलोड डायरेक्टरी आदि) को हटाकर
|
|
740
740
|
डिस्क स्थान खाली करता है, जबकि **वर्तमान में चल रहे कार्यों से संबंधित फ़ोल्डर**,
|
|
741
741
|
सुरक्षित सिस्टम पथ, और बिना कमिट या बिना पुश किए बदलावों वाले किसी भी क्लोन को बनाए
|
|
@@ -745,40 +745,40 @@ solve https://github.com/owner/repo/issues/123 --resume 657e6db1-6eb3-4a8d
|
|
|
745
745
|
|
|
746
746
|
```bash
|
|
747
747
|
# पूर्वावलोकन: रखे जाने वाले और हटाए जाने वाले फ़ोल्डरों की सूची (कुछ भी नहीं हटाता)
|
|
748
|
-
cleanup --dry-run
|
|
748
|
+
hive-cleanup --dry-run
|
|
749
749
|
|
|
750
750
|
# पुरानी अस्थायी फ़ाइलें वास्तव में हटाएँ (पहले पुष्टि माँगता है)
|
|
751
|
-
cleanup
|
|
751
|
+
hive-cleanup
|
|
752
752
|
|
|
753
753
|
# पुष्टि प्रॉम्प्ट के बिना हटाएँ
|
|
754
|
-
cleanup --force
|
|
754
|
+
hive-cleanup --force
|
|
755
755
|
|
|
756
756
|
# गैर-hive-mind अस्थायी प्रविष्टियों पर भी विचार करें (अधिक आक्रामक)
|
|
757
|
-
cleanup --all --dry-run
|
|
757
|
+
hive-cleanup --all --dry-run
|
|
758
758
|
|
|
759
759
|
# /tmp/start-command को हटाने की अनुमति दें (डिफ़ॉल्ट रूप से रखा जाता है; इसमें आइसोलेशन लॉग होते हैं)
|
|
760
|
-
cleanup --force-start-command
|
|
760
|
+
hive-cleanup --force-start-command
|
|
761
761
|
|
|
762
762
|
# Ubuntu / सिस्टम क्लीनअप (apt कैश, journald लॉग, npm कैश)
|
|
763
|
-
cleanup --system --sudo
|
|
763
|
+
hive-cleanup --system --sudo
|
|
764
764
|
|
|
765
765
|
# लाइव/अटके हुए agent PID को hive/start-command कार्य सत्रों से मिलाएँ
|
|
766
|
-
cleanup --processes
|
|
766
|
+
hive-cleanup --processes
|
|
767
767
|
|
|
768
768
|
# किसी खास non-agent PID को ट्रेस करें, जैसे browser child या shell
|
|
769
|
-
cleanup --pid 94445
|
|
769
|
+
hive-cleanup --pid 94445
|
|
770
770
|
|
|
771
771
|
# रोके जा सकने वाले orphaned agents का पूर्वावलोकन करें
|
|
772
|
-
cleanup --kill-orphaned-agents --dry-run
|
|
772
|
+
hive-cleanup --kill-orphaned-agents --dry-run
|
|
773
773
|
|
|
774
774
|
# पूर्वावलोकन जाँचने के बाद orphaned agent process trees रोकें
|
|
775
|
-
cleanup --kill-orphaned-agents --force
|
|
775
|
+
hive-cleanup --kill-orphaned-agents --force
|
|
776
776
|
|
|
777
777
|
# सक्रिय-कार्य पहचान अक्षम करें (केवल सुरक्षित पथ रखे जाते हैं)
|
|
778
|
-
cleanup --no-keep-active-tasks-folders --dry-run
|
|
778
|
+
hive-cleanup --no-keep-active-tasks-folders --dry-run
|
|
779
779
|
```
|
|
780
780
|
|
|
781
|
-
विकल्पों की पूरी सूची के लिए `cleanup --help` चलाएँ। यह कमांड dry-run के अनुकूल है और
|
|
781
|
+
विकल्पों की पूरी सूची के लिए `hive-cleanup --help` चलाएँ। यह कमांड dry-run के अनुकूल है और
|
|
782
782
|
हर रन के लिए टाइमस्टैम्प वाला `cleanup-*.log` लिखता है। प्रक्रिया डायग्नोस्टिक आउटपुट
|
|
783
783
|
कमांड लाइन प्रिंट करने से पहले सामान्य token आकारों को छिपाता है।
|
|
784
784
|
|
|
@@ -836,14 +836,14 @@ find docs/ -name "*.md" -exec wc -l {} + | awk '$1 > 1000 {print "ERROR: " $2 "
|
|
|
836
836
|
|
|
837
837
|
```bash
|
|
838
838
|
# agent PID, start-command session ID, GitHub task URL, workspace, match reasons और संभावित orphaned agents दिखाएँ।
|
|
839
|
-
cleanup --processes
|
|
839
|
+
hive-cleanup --processes
|
|
840
840
|
|
|
841
841
|
# उसी report में कोई भी PID शामिल करें।
|
|
842
|
-
cleanup --pid 62220
|
|
842
|
+
hive-cleanup --pid 62220
|
|
843
843
|
|
|
844
844
|
# केवल terminal task वाले orphaned agents रोकें।
|
|
845
|
-
cleanup --kill-orphaned-agents --dry-run
|
|
846
|
-
cleanup --kill-orphaned-agents --force
|
|
845
|
+
hive-cleanup --kill-orphaned-agents --dry-run
|
|
846
|
+
hive-cleanup --kill-orphaned-agents --force
|
|
847
847
|
```
|
|
848
848
|
|
|
849
849
|
Manual fallback: उन स्क्रीन की पहचान करें जो संसाधन खपत करने वाली प्रक्रियाओं के पैरेंट हैं।
|
package/README.md
CHANGED
|
@@ -755,7 +755,7 @@ solve https://github.com/owner/repo/issues/123 --resume 657e6db1-6eb3-4a8d
|
|
|
755
755
|
|
|
756
756
|
### Disk Cleanup
|
|
757
757
|
|
|
758
|
-
`cleanup` frees disk space by removing stale hive-mind temporary
|
|
758
|
+
`hive-cleanup` frees disk space by removing stale hive-mind temporary
|
|
759
759
|
directories/files (per-task clones like `/tmp/gh-issue-solver-*`, MCP config
|
|
760
760
|
files, log download dirs, …) while **keeping folders that belong to
|
|
761
761
|
currently-running tasks**, protected system paths, and any clone with
|
|
@@ -766,40 +766,40 @@ branch).
|
|
|
766
766
|
|
|
767
767
|
```bash
|
|
768
768
|
# Preview: list kept folders and folders that would be deleted (deletes nothing)
|
|
769
|
-
cleanup --dry-run
|
|
769
|
+
hive-cleanup --dry-run
|
|
770
770
|
|
|
771
771
|
# Actually delete stale temp artifacts (asks for confirmation first)
|
|
772
|
-
cleanup
|
|
772
|
+
hive-cleanup
|
|
773
773
|
|
|
774
774
|
# Delete without the confirmation prompt
|
|
775
|
-
cleanup --force
|
|
775
|
+
hive-cleanup --force
|
|
776
776
|
|
|
777
777
|
# Also consider non-hive-mind temp entries (more aggressive)
|
|
778
|
-
cleanup --all --dry-run
|
|
778
|
+
hive-cleanup --all --dry-run
|
|
779
779
|
|
|
780
780
|
# Allow deleting /tmp/start-command (kept by default; holds isolation logs)
|
|
781
|
-
cleanup --force-start-command
|
|
781
|
+
hive-cleanup --force-start-command
|
|
782
782
|
|
|
783
783
|
# Ubuntu / system cleanup (apt caches, journald logs, npm cache)
|
|
784
|
-
cleanup --system --sudo
|
|
784
|
+
hive-cleanup --system --sudo
|
|
785
785
|
|
|
786
786
|
# Map live/stuck agent PIDs back to hive/start-command task sessions
|
|
787
|
-
cleanup --processes
|
|
787
|
+
hive-cleanup --processes
|
|
788
788
|
|
|
789
789
|
# Trace a specific non-agent PID, for example a browser child or shell
|
|
790
|
-
cleanup --pid 94445
|
|
790
|
+
hive-cleanup --pid 94445
|
|
791
791
|
|
|
792
792
|
# Preview orphaned terminal-session agents that can be stopped
|
|
793
|
-
cleanup --kill-orphaned-agents --dry-run
|
|
793
|
+
hive-cleanup --kill-orphaned-agents --dry-run
|
|
794
794
|
|
|
795
795
|
# Stop orphaned agent process trees after reviewing the preview
|
|
796
|
-
cleanup --kill-orphaned-agents --force
|
|
796
|
+
hive-cleanup --kill-orphaned-agents --force
|
|
797
797
|
|
|
798
798
|
# Disable active-task detection (only protected paths are kept)
|
|
799
|
-
cleanup --no-keep-active-tasks-folders --dry-run
|
|
799
|
+
hive-cleanup --no-keep-active-tasks-folders --dry-run
|
|
800
800
|
```
|
|
801
801
|
|
|
802
|
-
Run `cleanup --help` for the full list of options. The command is dry-run
|
|
802
|
+
Run `hive-cleanup --help` for the full list of options. The command is dry-run
|
|
803
803
|
friendly and writes a timestamped `cleanup-*.log` for every run. Process
|
|
804
804
|
diagnostic output redacts common token shapes before printing command lines.
|
|
805
805
|
|
|
@@ -859,14 +859,14 @@ that launched it:
|
|
|
859
859
|
```bash
|
|
860
860
|
# Show agent PIDs, start-command session IDs, GitHub task URLs, workspaces,
|
|
861
861
|
# match reasons, and possible orphaned terminal-session agents.
|
|
862
|
-
cleanup --processes
|
|
862
|
+
hive-cleanup --processes
|
|
863
863
|
|
|
864
864
|
# Include an arbitrary PID in the same report.
|
|
865
|
-
cleanup --pid 62220
|
|
865
|
+
hive-cleanup --pid 62220
|
|
866
866
|
|
|
867
867
|
# Kill only agents whose matched start-command task is already terminal.
|
|
868
|
-
cleanup --kill-orphaned-agents --dry-run
|
|
869
|
-
cleanup --kill-orphaned-agents --force
|
|
868
|
+
hive-cleanup --kill-orphaned-agents --dry-run
|
|
869
|
+
hive-cleanup --kill-orphaned-agents --force
|
|
870
870
|
```
|
|
871
871
|
|
|
872
872
|
Manual fallback: identify screens that are parents of processes that are eating
|
package/README.ru.md
CHANGED
|
@@ -737,7 +737,7 @@ solve https://github.com/owner/repo/issues/123 --resume 657e6db1-6eb3-4a8d
|
|
|
737
737
|
|
|
738
738
|
### Очистка диска
|
|
739
739
|
|
|
740
|
-
`cleanup` освобождает место на диске, удаляя устаревшие временные каталоги/файлы
|
|
740
|
+
`hive-cleanup` освобождает место на диске, удаляя устаревшие временные каталоги/файлы
|
|
741
741
|
hive-mind (клоны для каждой задачи вида `/tmp/gh-issue-solver-*`, файлы
|
|
742
742
|
конфигурации MCP, каталоги загрузки логов и т. д.), при этом **сохраняя папки,
|
|
743
743
|
относящиеся к выполняющимся в данный момент задачам**, защищённые системные пути и
|
|
@@ -748,40 +748,40 @@ hive-mind (клоны для каждой задачи вида `/tmp/gh-issue-s
|
|
|
748
748
|
|
|
749
749
|
```bash
|
|
750
750
|
# Предпросмотр: список сохраняемых и удаляемых папок (ничего не удаляет)
|
|
751
|
-
cleanup --dry-run
|
|
751
|
+
hive-cleanup --dry-run
|
|
752
752
|
|
|
753
753
|
# Реально удалить устаревшие временные файлы (сначала запросит подтверждение)
|
|
754
|
-
cleanup
|
|
754
|
+
hive-cleanup
|
|
755
755
|
|
|
756
756
|
# Удалить без запроса подтверждения
|
|
757
|
-
cleanup --force
|
|
757
|
+
hive-cleanup --force
|
|
758
758
|
|
|
759
759
|
# Учитывать также не-hive-mind временные записи (более агрессивно)
|
|
760
|
-
cleanup --all --dry-run
|
|
760
|
+
hive-cleanup --all --dry-run
|
|
761
761
|
|
|
762
762
|
# Разрешить удаление /tmp/start-command (по умолчанию сохраняется; хранит логи изоляции)
|
|
763
|
-
cleanup --force-start-command
|
|
763
|
+
hive-cleanup --force-start-command
|
|
764
764
|
|
|
765
765
|
# Очистка Ubuntu / системы (кэши apt, логи journald, кэш npm)
|
|
766
|
-
cleanup --system --sudo
|
|
766
|
+
hive-cleanup --system --sudo
|
|
767
767
|
|
|
768
768
|
# Сопоставить живые/зависшие agent PID с задачами hive/start-command
|
|
769
|
-
cleanup --processes
|
|
769
|
+
hive-cleanup --processes
|
|
770
770
|
|
|
771
771
|
# Отследить конкретный не-agent PID, например дочерний процесс браузера или shell
|
|
772
|
-
cleanup --pid 94445
|
|
772
|
+
hive-cleanup --pid 94445
|
|
773
773
|
|
|
774
774
|
# Предпросмотр orphaned agents, которые можно остановить
|
|
775
|
-
cleanup --kill-orphaned-agents --dry-run
|
|
775
|
+
hive-cleanup --kill-orphaned-agents --dry-run
|
|
776
776
|
|
|
777
777
|
# Остановить деревья orphaned agent процессов после просмотра предпросмотра
|
|
778
|
-
cleanup --kill-orphaned-agents --force
|
|
778
|
+
hive-cleanup --kill-orphaned-agents --force
|
|
779
779
|
|
|
780
780
|
# Отключить обнаружение активных задач (сохраняются только защищённые пути)
|
|
781
|
-
cleanup --no-keep-active-tasks-folders --dry-run
|
|
781
|
+
hive-cleanup --no-keep-active-tasks-folders --dry-run
|
|
782
782
|
```
|
|
783
783
|
|
|
784
|
-
Запустите `cleanup --help`, чтобы увидеть полный список опций. Команда удобна для
|
|
784
|
+
Запустите `hive-cleanup --help`, чтобы увидеть полный список опций. Команда удобна для
|
|
785
785
|
режима dry-run и записывает лог `cleanup-*.log` с меткой времени при каждом запуске.
|
|
786
786
|
Диагностический вывод процессов скрывает распространённые формы token перед печатью
|
|
787
787
|
командных строк.
|
|
@@ -841,14 +841,14 @@ find docs/ -name "*.md" -exec wc -l {} + | awk '$1 > 1000 {print "ERROR: " $2 "
|
|
|
841
841
|
```bash
|
|
842
842
|
# Показать agent PID, start-command session ID, GitHub task URL, workspace,
|
|
843
843
|
# причины совпадения и возможные orphaned agents.
|
|
844
|
-
cleanup --processes
|
|
844
|
+
hive-cleanup --processes
|
|
845
845
|
|
|
846
846
|
# Включить произвольный PID в тот же отчёт.
|
|
847
|
-
cleanup --pid 62220
|
|
847
|
+
hive-cleanup --pid 62220
|
|
848
848
|
|
|
849
849
|
# Остановить только orphaned agents, чья задача уже завершена.
|
|
850
|
-
cleanup --kill-orphaned-agents --dry-run
|
|
851
|
-
cleanup --kill-orphaned-agents --force
|
|
850
|
+
hive-cleanup --kill-orphaned-agents --dry-run
|
|
851
|
+
hive-cleanup --kill-orphaned-agents --force
|
|
852
852
|
```
|
|
853
853
|
|
|
854
854
|
Ручной fallback: определите screen-сессии, являющиеся родительскими для процессов,
|
package/README.zh.md
CHANGED
|
@@ -730,7 +730,7 @@ solve https://github.com/owner/repo/issues/123 --resume 657e6db1-6eb3-4a8d
|
|
|
730
730
|
|
|
731
731
|
### 磁盘清理
|
|
732
732
|
|
|
733
|
-
`cleanup` 通过删除过时的 hive-mind 临时目录/文件(如每个任务的克隆
|
|
733
|
+
`hive-cleanup` 通过删除过时的 hive-mind 临时目录/文件(如每个任务的克隆
|
|
734
734
|
`/tmp/gh-issue-solver-*`、MCP 配置文件、日志下载目录等)来释放磁盘空间,同时
|
|
735
735
|
**保留属于当前正在运行任务的文件夹**、受保护的系统路径,以及任何包含未提交或未推送
|
|
736
736
|
更改的克隆。它通过运行中的进程和实时隔离会话检测活动任务,并使用与 `solve` 相同的
|
|
@@ -739,40 +739,40 @@ solve https://github.com/owner/repo/issues/123 --resume 657e6db1-6eb3-4a8d
|
|
|
739
739
|
|
|
740
740
|
```bash
|
|
741
741
|
# 预览:列出保留的文件夹和将被删除的文件夹(不删除任何内容)
|
|
742
|
-
cleanup --dry-run
|
|
742
|
+
hive-cleanup --dry-run
|
|
743
743
|
|
|
744
744
|
# 实际删除过时的临时文件(会先要求确认)
|
|
745
|
-
cleanup
|
|
745
|
+
hive-cleanup
|
|
746
746
|
|
|
747
747
|
# 删除时不显示确认提示
|
|
748
|
-
cleanup --force
|
|
748
|
+
hive-cleanup --force
|
|
749
749
|
|
|
750
750
|
# 同时考虑非 hive-mind 临时项(更激进)
|
|
751
|
-
cleanup --all --dry-run
|
|
751
|
+
hive-cleanup --all --dry-run
|
|
752
752
|
|
|
753
753
|
# 允许删除 /tmp/start-command(默认保留;其中存放隔离日志)
|
|
754
|
-
cleanup --force-start-command
|
|
754
|
+
hive-cleanup --force-start-command
|
|
755
755
|
|
|
756
756
|
# Ubuntu / 系统清理(apt 缓存、journald 日志、npm 缓存)
|
|
757
|
-
cleanup --system --sudo
|
|
757
|
+
hive-cleanup --system --sudo
|
|
758
758
|
|
|
759
759
|
# 将实时/卡住的 agent PID 映射回 hive/start-command 任务会话
|
|
760
|
-
cleanup --processes
|
|
760
|
+
hive-cleanup --processes
|
|
761
761
|
|
|
762
762
|
# 跟踪指定的非 agent PID,例如浏览器子进程或 shell
|
|
763
|
-
cleanup --pid 94445
|
|
763
|
+
hive-cleanup --pid 94445
|
|
764
764
|
|
|
765
765
|
# 预览可以停止的孤立 agent
|
|
766
|
-
cleanup --kill-orphaned-agents --dry-run
|
|
766
|
+
hive-cleanup --kill-orphaned-agents --dry-run
|
|
767
767
|
|
|
768
768
|
# 审查预览后停止孤立 agent 进程树
|
|
769
|
-
cleanup --kill-orphaned-agents --force
|
|
769
|
+
hive-cleanup --kill-orphaned-agents --force
|
|
770
770
|
|
|
771
771
|
# 禁用活动任务检测(仅保留受保护的路径)
|
|
772
|
-
cleanup --no-keep-active-tasks-folders --dry-run
|
|
772
|
+
hive-cleanup --no-keep-active-tasks-folders --dry-run
|
|
773
773
|
```
|
|
774
774
|
|
|
775
|
-
运行 `cleanup --help` 查看完整的选项列表。该命令对 dry-run 友好,并为每次运行写入
|
|
775
|
+
运行 `hive-cleanup --help` 查看完整的选项列表。该命令对 dry-run 友好,并为每次运行写入
|
|
776
776
|
带时间戳的 `cleanup-*.log` 日志。进程诊断输出会在打印命令行前遮蔽常见 token
|
|
777
777
|
格式。
|
|
778
778
|
|
|
@@ -830,14 +830,14 @@ hive 任务时,优先使用内置进程诊断命令:
|
|
|
830
830
|
|
|
831
831
|
```bash
|
|
832
832
|
# 显示 agent PID、start-command 会话 ID、GitHub 任务 URL、工作区、匹配原因和可能的孤立 agent。
|
|
833
|
-
cleanup --processes
|
|
833
|
+
hive-cleanup --processes
|
|
834
834
|
|
|
835
835
|
# 在同一报告中包含任意 PID。
|
|
836
|
-
cleanup --pid 62220
|
|
836
|
+
hive-cleanup --pid 62220
|
|
837
837
|
|
|
838
838
|
# 只停止已完成任务中的孤立 agent。
|
|
839
|
-
cleanup --kill-orphaned-agents --dry-run
|
|
840
|
-
cleanup --kill-orphaned-agents --force
|
|
839
|
+
hive-cleanup --kill-orphaned-agents --dry-run
|
|
840
|
+
hive-cleanup --kill-orphaned-agents --force
|
|
841
841
|
```
|
|
842
842
|
|
|
843
843
|
手动兜底:识别消耗资源的进程所属的 Screen 会话。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@link-assistant/hive-mind",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "AI-powered issue solver and hive mind for collaborative problem solving",
|
|
5
5
|
"main": "src/hive.mjs",
|
|
6
6
|
"type": "module",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"hive": "./src/hive.mjs",
|
|
9
9
|
"solve": "./src/solve.mjs",
|
|
10
10
|
"task": "./src/task.mjs",
|
|
11
|
-
"cleanup": "./src/cleanup.mjs",
|
|
11
|
+
"hive-cleanup": "./src/cleanup.mjs",
|
|
12
12
|
"review": "./src/review.mjs",
|
|
13
13
|
"configure-claude": "./src/configure-claude.mjs",
|
|
14
14
|
"start-screen": "./src/start-screen.mjs",
|
package/src/cleanup.lib.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Core, offline-testable logic for the `cleanup` command (issue #1848).
|
|
2
|
+
* Core, offline-testable logic for the `hive-cleanup` command (issue #1848).
|
|
3
3
|
*
|
|
4
4
|
* This module deliberately avoids any top-level network access (no `use-m`
|
|
5
5
|
* fetch) and any side effects so it can be unit-tested without a network
|
|
@@ -144,8 +144,8 @@ function sameRepo(a, b) {
|
|
|
144
144
|
* fall back to the `issue-{number}-{hex}` prefix (the random hex is unknown from
|
|
145
145
|
* the URL alone) combined with a repo match.
|
|
146
146
|
*
|
|
147
|
-
* @param {Array<{owner, repo, type, number, branch?: string|null}>} activeTasks
|
|
148
|
-
* @returns {Array<{owner, repo, type, issueNumber: number|null, branch: string|null}>}
|
|
147
|
+
* @param {Array<{owner, repo, type, number, branch?: string|null, sessionId?: string|null, sessionName?: string|null, status?: string|null, workspace?: string|null}>} activeTasks
|
|
148
|
+
* @returns {Array<{owner, repo, type, number: number|null, issueNumber: number|null, branch: string|null, sessionId: string|null, sessionName: string|null, status: string|null, workspace: string|null}>}
|
|
149
149
|
*/
|
|
150
150
|
export function buildActiveMatchers(activeTasks) {
|
|
151
151
|
const matchers = [];
|
|
@@ -155,8 +155,13 @@ export function buildActiveMatchers(activeTasks) {
|
|
|
155
155
|
owner: task.owner,
|
|
156
156
|
repo: task.repo,
|
|
157
157
|
type: task.type,
|
|
158
|
+
number: task.number ?? null,
|
|
158
159
|
issueNumber: task.type === 'issue' ? task.number : (task.issueNumber ?? null),
|
|
159
160
|
branch: task.branch || null,
|
|
161
|
+
sessionId: task.sessionId || null,
|
|
162
|
+
sessionName: task.sessionName || null,
|
|
163
|
+
status: task.status || null,
|
|
164
|
+
workspace: task.workspace || null,
|
|
160
165
|
});
|
|
161
166
|
}
|
|
162
167
|
return matchers;
|
|
@@ -291,9 +296,12 @@ export function classifyEntry(entry, ctx) {
|
|
|
291
296
|
export function classifyEntries(entries, ctx) {
|
|
292
297
|
const keep = [];
|
|
293
298
|
const remove = [];
|
|
299
|
+
const { matchers = [], gitInfoByPath = new Map() } = ctx || {};
|
|
294
300
|
for (const entry of entries || []) {
|
|
295
301
|
const { action, reason } = classifyEntry(entry, ctx);
|
|
296
|
-
const
|
|
302
|
+
const gitInfo = gitInfoByPath.get(entry.path) || null;
|
|
303
|
+
const activeTask = reason === 'active-task' ? folderMatchesActiveTask(gitInfo, matchers) : null;
|
|
304
|
+
const record = { name: entry.name, path: entry.path, size: entry.size ?? null, reason, gitInfo, activeTask };
|
|
297
305
|
if (action === 'remove') remove.push(record);
|
|
298
306
|
else keep.push(record);
|
|
299
307
|
}
|
|
@@ -357,3 +365,51 @@ export function describeReason(reason) {
|
|
|
357
365
|
};
|
|
358
366
|
return map[reason] || reason;
|
|
359
367
|
}
|
|
368
|
+
|
|
369
|
+
function firstRemote(gitInfo) {
|
|
370
|
+
return gitInfo?.remotes?.[0] || null;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
function compactTaskType(type) {
|
|
374
|
+
return type === 'pull' ? 'PR' : 'issue';
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Format an active task for logs.
|
|
379
|
+
*
|
|
380
|
+
* @param {{owner?: string, repo?: string, type?: string, number?: number|null, issueNumber?: number|null, branch?: string|null, sessionId?: string|null, sessionName?: string|null, status?: string|null, workspace?: string|null}} task
|
|
381
|
+
* @returns {string}
|
|
382
|
+
*/
|
|
383
|
+
export function formatTaskSummary(task) {
|
|
384
|
+
if (!task) return '';
|
|
385
|
+
const number = task.number ?? task.issueNumber ?? null;
|
|
386
|
+
const parts = [`${task.owner}/${task.repo} ${compactTaskType(task.type)} #${number ?? '?'}`];
|
|
387
|
+
if (task.branch) parts.push(`branch ${task.branch}`);
|
|
388
|
+
if (task.sessionId || task.sessionName) parts.push(`session ${task.sessionId || task.sessionName}`);
|
|
389
|
+
if (task.status) parts.push(`status ${task.status}`);
|
|
390
|
+
if (task.workspace) parts.push(`workspace ${task.workspace}`);
|
|
391
|
+
return parts.join(', ');
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Format per-entry git/task context for one-line cleanup reports.
|
|
396
|
+
*
|
|
397
|
+
* @param {{gitInfo?: {branch?: string|null, remotes?: Array<{owner, repo}>|null, dirty?: boolean}|null, activeTask?: Object|null}} item
|
|
398
|
+
* @returns {string}
|
|
399
|
+
*/
|
|
400
|
+
export function formatEntryContext(item) {
|
|
401
|
+
const details = [];
|
|
402
|
+
if (item?.activeTask) details.push(`task ${formatTaskSummary(item.activeTask)}`);
|
|
403
|
+
|
|
404
|
+
const gitInfo = item?.gitInfo;
|
|
405
|
+
if (gitInfo) {
|
|
406
|
+
const remote = firstRemote(gitInfo);
|
|
407
|
+
const gitParts = [];
|
|
408
|
+
if (remote) gitParts.push(`repo ${remote.owner}/${remote.repo}`);
|
|
409
|
+
if (gitInfo.branch) gitParts.push(`branch ${gitInfo.branch}`);
|
|
410
|
+
if (gitInfo.dirty) gitParts.push('dirty/unpushed');
|
|
411
|
+
if (gitParts.length > 0) details.push(gitParts.join(', '));
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
return details.length > 0 ? ` (${details.join('; ')})` : '';
|
|
415
|
+
}
|
package/src/cleanup.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* `cleanup` — free disk space by removing stale hive-mind temporary
|
|
3
|
+
* `hive-cleanup` — free disk space by removing stale hive-mind temporary
|
|
4
4
|
* directories/files while preserving folders that belong to currently-running
|
|
5
5
|
* (active) tasks, protected system paths and any work that is not yet pushed.
|
|
6
6
|
*
|
|
@@ -33,9 +33,9 @@
|
|
|
33
33
|
|
|
34
34
|
import path from 'node:path';
|
|
35
35
|
import { promises as fsp } from 'node:fs';
|
|
36
|
-
import { execSync } from 'node:child_process';
|
|
37
36
|
|
|
38
|
-
import {
|
|
37
|
+
import { isConfirmationYes, readConfirmationLine } from './confirmation.lib.mjs';
|
|
38
|
+
import { classifyEntries, summarize, formatBytes, describeReason, buildActiveMatchers, DEFAULT_PROTECTED_NAMES, formatEntryContext, formatTaskSummary } from './cleanup.lib.mjs';
|
|
39
39
|
import { getTempRoot, listTempEntries, getPathSize, readFolderGitInfo, listProcessHeldPaths, getActiveTasks, removePath, runSystemCleanup, collectProcessDebugReport, signalOrphanedAgentTrees } from './cleanup.os.lib.mjs';
|
|
40
40
|
import { formatProcessDebugReport } from './process-debug.lib.mjs';
|
|
41
41
|
|
|
@@ -86,7 +86,7 @@ if (hasFlag('--version')) {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
if (hasFlag('--help', '-h')) {
|
|
89
|
-
console.log(`Usage: cleanup [options]
|
|
89
|
+
console.log(`Usage: hive-cleanup [options]
|
|
90
90
|
|
|
91
91
|
Free disk space by removing stale hive-mind temporary directories/files while
|
|
92
92
|
keeping folders that belong to active tasks and protected system paths.
|
|
@@ -244,8 +244,8 @@ async function main() {
|
|
|
244
244
|
matchers = buildActiveMatchers(activeTasks);
|
|
245
245
|
if (activeTasks.length > 0) {
|
|
246
246
|
await log(`🏃 Active tasks detected: ${activeTasks.length}`);
|
|
247
|
-
for (const
|
|
248
|
-
await log(` • ${
|
|
247
|
+
for (const task of activeTasks) {
|
|
248
|
+
await log(` • ${formatTaskSummary(task)}`);
|
|
249
249
|
}
|
|
250
250
|
} else {
|
|
251
251
|
await log('🏃 No active tasks detected from running processes/sessions');
|
|
@@ -289,13 +289,13 @@ async function main() {
|
|
|
289
289
|
await log('\n🟢 KEPT folders/files:');
|
|
290
290
|
if (classified.keep.length === 0) await log(' (none)');
|
|
291
291
|
for (const item of classified.keep.sort((a, b) => (b.size || 0) - (a.size || 0))) {
|
|
292
|
-
await log(` ${formatBytes(item.size).padStart(7)} ${item.path} — ${describeReason(item.reason)}`);
|
|
292
|
+
await log(` ${formatBytes(item.size).padStart(7)} ${item.path} — ${describeReason(item.reason)}${formatEntryContext(item)}`);
|
|
293
293
|
}
|
|
294
294
|
|
|
295
295
|
await log(`\n🗑️ ${options.dryRun ? 'WOULD DELETE' : 'TO DELETE'} folders/files:`);
|
|
296
296
|
if (classified.remove.length === 0) await log(' (none)');
|
|
297
297
|
for (const item of classified.remove.sort((a, b) => (b.size || 0) - (a.size || 0))) {
|
|
298
|
-
await log(` ${formatBytes(item.size).padStart(7)} ${item.path} — ${describeReason(item.reason)}`);
|
|
298
|
+
await log(` ${formatBytes(item.size).padStart(7)} ${item.path} — ${describeReason(item.reason)}${formatEntryContext(item)}`);
|
|
299
299
|
}
|
|
300
300
|
|
|
301
301
|
await log(`\n📊 Summary: keep ${totals.keepCount} (${formatBytes(totals.keepBytes)}), remove ${totals.removeCount} (${formatBytes(totals.removeBytes)})`);
|
|
@@ -309,15 +309,14 @@ async function main() {
|
|
|
309
309
|
if (!options.force) {
|
|
310
310
|
console.log(`\n⚠️ This will permanently delete ${classified.remove.length} entries (${formatBytes(totals.removeBytes)}).`);
|
|
311
311
|
console.log('Type "yes" to confirm, or Ctrl+C to cancel:');
|
|
312
|
-
process.stdout.write('> ');
|
|
313
312
|
let answer = '';
|
|
314
313
|
try {
|
|
315
|
-
answer =
|
|
314
|
+
answer = await readConfirmationLine({ prompt: '> ' });
|
|
316
315
|
} catch {
|
|
317
316
|
await log('\n❌ Cancelled');
|
|
318
317
|
return;
|
|
319
318
|
}
|
|
320
|
-
if (answer
|
|
319
|
+
if (!isConfirmationYes(answer)) {
|
|
321
320
|
await log('\n❌ Cancelled');
|
|
322
321
|
return;
|
|
323
322
|
}
|
package/src/cleanup.os.lib.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* OS-interaction layer for the `cleanup` command (issue #1848).
|
|
2
|
+
* OS-interaction layer for the `hive-cleanup` command (issue #1848).
|
|
3
3
|
*
|
|
4
4
|
* Everything that touches the real filesystem, the process table (/proc),
|
|
5
5
|
* isolation session state (`$ --status` from start-command), git metadata of a
|
|
@@ -625,7 +625,13 @@ export async function listActiveTaskRefsFromSessions(sessionIds) {
|
|
|
625
625
|
const key = `${ref.owner}/${ref.repo}#${ref.number}:${ref.type}`;
|
|
626
626
|
if (!seen.has(key)) {
|
|
627
627
|
seen.add(key);
|
|
628
|
-
refs.push(
|
|
628
|
+
refs.push({
|
|
629
|
+
...ref,
|
|
630
|
+
sessionId: status.uuid || id,
|
|
631
|
+
sessionName: status.sessionName || id,
|
|
632
|
+
status: status.status || null,
|
|
633
|
+
workspace: status.workingDirectory || null,
|
|
634
|
+
});
|
|
629
635
|
}
|
|
630
636
|
}
|
|
631
637
|
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared helpers for destructive CLI confirmations.
|
|
3
|
+
*
|
|
4
|
+
* @see https://github.com/link-assistant/hive-mind/issues/1930
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { createInterface } from 'node:readline/promises';
|
|
8
|
+
import { stdin, stdout } from 'node:process';
|
|
9
|
+
|
|
10
|
+
const ESC = String.fromCharCode(0x1b);
|
|
11
|
+
const BEL = String.fromCharCode(0x07);
|
|
12
|
+
const C1_CSI = String.fromCharCode(0x9b);
|
|
13
|
+
|
|
14
|
+
const ANSI_ESCAPE_PATTERN = new RegExp(`${ESC}(?:\\[[0-?]*[ -/]*[@-~]|\\][^${BEL}]*(?:${BEL}|${ESC}\\\\)|[@-Z\\\\-_])`, 'g');
|
|
15
|
+
const C1_CSI_PATTERN = new RegExp(`${C1_CSI}[0-?]*[ -/]*[@-~]`, 'g');
|
|
16
|
+
|
|
17
|
+
function removeLastWord(chars) {
|
|
18
|
+
while (chars.length > 0 && /\s/.test(chars.at(-1))) chars.pop();
|
|
19
|
+
while (chars.length > 0 && !/\s/.test(chars.at(-1))) chars.pop();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Normalize an answer as it appeared after terminal line editing.
|
|
24
|
+
*
|
|
25
|
+
* Some terminal/window-manager shortcuts can inject escape sequences into the
|
|
26
|
+
* input stream even though the user still sees a clean `yes`. We strip those
|
|
27
|
+
* non-text sequences and replay common erase controls before comparing.
|
|
28
|
+
*
|
|
29
|
+
* @param {unknown} value
|
|
30
|
+
* @returns {string}
|
|
31
|
+
*/
|
|
32
|
+
export function normalizeConfirmationInput(value) {
|
|
33
|
+
const raw = String(value ?? '')
|
|
34
|
+
.normalize('NFKC')
|
|
35
|
+
.replace(ANSI_ESCAPE_PATTERN, '')
|
|
36
|
+
.replace(C1_CSI_PATTERN, '');
|
|
37
|
+
const chars = [];
|
|
38
|
+
|
|
39
|
+
for (const char of raw) {
|
|
40
|
+
const code = char.codePointAt(0);
|
|
41
|
+
|
|
42
|
+
if (char === '\b' || char === '\u007f') {
|
|
43
|
+
chars.pop();
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (char === '\u0015') {
|
|
48
|
+
chars.length = 0;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (char === '\u0017') {
|
|
53
|
+
removeLastWord(chars);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (char === '\r' || char === '\n' || code === 0xfeff) continue;
|
|
58
|
+
if (code < 32 || (code >= 0x80 && code <= 0x9f)) continue;
|
|
59
|
+
|
|
60
|
+
chars.push(char);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return chars.join('').trim();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function isConfirmationYes(value) {
|
|
67
|
+
return normalizeConfirmationInput(value).toLowerCase() === 'yes';
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Read one interactive confirmation line.
|
|
72
|
+
*
|
|
73
|
+
* @param {{prompt?: string, input?: import('node:stream').Readable, output?: import('node:stream').Writable}} [options]
|
|
74
|
+
* @returns {Promise<string>}
|
|
75
|
+
*/
|
|
76
|
+
export async function readConfirmationLine(options = {}) {
|
|
77
|
+
const input = options.input || stdin;
|
|
78
|
+
const output = options.output || stdout;
|
|
79
|
+
const rl = createInterface({
|
|
80
|
+
input,
|
|
81
|
+
output,
|
|
82
|
+
terminal: Boolean(input.isTTY && output.isTTY),
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
return await rl.question(options.prompt ?? '> ');
|
|
87
|
+
} finally {
|
|
88
|
+
rl.close();
|
|
89
|
+
}
|
|
90
|
+
}
|