codeksei 0.1.0 → 0.1.1
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/LICENSE +661 -661
- package/README.en.md +109 -47
- package/README.md +79 -58
- package/bin/cyberboss.js +1 -1
- package/package.json +86 -86
- package/scripts/open_shared_wechat_thread.sh +77 -77
- package/scripts/open_wechat_thread.sh +108 -108
- package/scripts/shared-common.js +144 -144
- package/scripts/shared-open.js +14 -14
- package/scripts/shared-start.js +5 -5
- package/scripts/shared-status.js +27 -27
- package/scripts/show_shared_status.sh +45 -45
- package/scripts/start_shared_app_server.sh +52 -52
- package/scripts/start_shared_wechat.sh +94 -94
- package/scripts/timeline-screenshot.sh +14 -14
- package/src/adapters/channel/weixin/account-store.js +99 -99
- package/src/adapters/channel/weixin/api-v2.js +50 -50
- package/src/adapters/channel/weixin/api.js +169 -169
- package/src/adapters/channel/weixin/context-token-store.js +84 -84
- package/src/adapters/channel/weixin/index.js +618 -604
- package/src/adapters/channel/weixin/legacy.js +579 -566
- package/src/adapters/channel/weixin/media-mime.js +22 -22
- package/src/adapters/channel/weixin/media-receive.js +370 -370
- package/src/adapters/channel/weixin/media-send.js +102 -102
- package/src/adapters/channel/weixin/message-utils-v2.js +282 -282
- package/src/adapters/channel/weixin/message-utils.js +199 -199
- package/src/adapters/channel/weixin/redact.js +41 -41
- package/src/adapters/channel/weixin/reminder-queue-store.js +101 -101
- package/src/adapters/channel/weixin/sync-buffer-store.js +35 -35
- package/src/adapters/runtime/codex/events.js +215 -215
- package/src/adapters/runtime/codex/index.js +109 -104
- package/src/adapters/runtime/codex/message-utils.js +95 -95
- package/src/adapters/runtime/codex/model-catalog.js +106 -106
- package/src/adapters/runtime/codex/protocol-leak-monitor.js +75 -75
- package/src/adapters/runtime/codex/rpc-client.js +339 -339
- package/src/adapters/runtime/codex/session-store.js +286 -286
- package/src/app/channel-send-file-cli.js +57 -57
- package/src/app/diary-write-cli.js +236 -88
- package/src/app/note-sync-cli.js +2 -2
- package/src/app/reminder-write-cli.js +215 -210
- package/src/app/review-cli.js +7 -5
- package/src/app/system-checkin-poller.js +64 -64
- package/src/app/system-send-cli.js +129 -129
- package/src/app/timeline-event-cli.js +28 -25
- package/src/app/timeline-screenshot-cli.js +103 -100
- package/src/core/app.js +1763 -1763
- package/src/core/branding.js +2 -1
- package/src/core/command-registry.js +381 -369
- package/src/core/config.js +30 -14
- package/src/core/default-targets.js +163 -163
- package/src/core/durable-note-schema.js +9 -8
- package/src/core/instructions-template.js +17 -16
- package/src/core/note-sync.js +8 -7
- package/src/core/path-utils.js +54 -0
- package/src/core/project-radar.js +11 -10
- package/src/core/review.js +48 -50
- package/src/core/stream-delivery.js +1162 -983
- package/src/core/system-message-dispatcher.js +68 -68
- package/src/core/system-message-queue-store.js +128 -128
- package/src/core/thread-state-store.js +96 -96
- package/src/core/timeline-screenshot-queue-store.js +134 -134
- package/src/core/timezone.js +436 -0
- package/src/core/workspace-bootstrap.js +9 -1
- package/src/index.js +148 -146
- package/src/integrations/timeline/index.js +130 -74
- package/src/integrations/timeline/state-sync.js +240 -0
- package/templates/weixin-instructions.md +12 -38
- package/templates/weixin-operations.md +29 -31
package/package.json
CHANGED
|
@@ -1,86 +1,86 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "codeksei",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Local-first life-assistant agent bridge for Codex, WeChat, timeline, diary, and review workflows.",
|
|
5
|
-
"license": "AGPL-3.0-only",
|
|
6
|
-
"private": false,
|
|
7
|
-
"type": "commonjs",
|
|
8
|
-
"main": "src/index.js",
|
|
9
|
-
"repository": {
|
|
10
|
-
"type": "git",
|
|
11
|
-
"url": "git+https://github.com/Sapientropic/codeksei.git"
|
|
12
|
-
},
|
|
13
|
-
"homepage": "https://github.com/Sapientropic/codeksei#readme",
|
|
14
|
-
"bugs": {
|
|
15
|
-
"url": "https://github.com/Sapientropic/codeksei/issues"
|
|
16
|
-
},
|
|
17
|
-
"bin": {
|
|
18
|
-
"codeksei": "bin/codeksei.js",
|
|
19
|
-
"cyberboss": "bin/cyberboss.js"
|
|
20
|
-
},
|
|
21
|
-
"files": [
|
|
22
|
-
"bin",
|
|
23
|
-
"src",
|
|
24
|
-
"scripts",
|
|
25
|
-
"templates",
|
|
26
|
-
"README.en.md"
|
|
27
|
-
],
|
|
28
|
-
"keywords": [
|
|
29
|
-
"codeksei",
|
|
30
|
-
"codex",
|
|
31
|
-
"wechat",
|
|
32
|
-
"weixin",
|
|
33
|
-
"timeline",
|
|
34
|
-
"review",
|
|
35
|
-
"life-assistant"
|
|
36
|
-
],
|
|
37
|
-
"engines": {
|
|
38
|
-
"node": ">=22"
|
|
39
|
-
},
|
|
40
|
-
"publishConfig": {
|
|
41
|
-
"access": "public"
|
|
42
|
-
},
|
|
43
|
-
"scripts": {
|
|
44
|
-
"start": "node ./bin/codeksei.js start",
|
|
45
|
-
"start:checkin": "node ./bin/codeksei.js start --checkin",
|
|
46
|
-
"login": "node ./bin/codeksei.js login",
|
|
47
|
-
"accounts": "node ./bin/codeksei.js accounts",
|
|
48
|
-
"doctor": "node ./bin/codeksei.js doctor",
|
|
49
|
-
"help": "node ./bin/codeksei.js help",
|
|
50
|
-
"shared:start": "node ./scripts/shared-start.js",
|
|
51
|
-
"shared:open": "node ./scripts/shared-open.js",
|
|
52
|
-
"shared:status": "node ./scripts/shared-status.js",
|
|
53
|
-
"shared:supervisor": "node ./scripts/shared-supervisor.js",
|
|
54
|
-
"shared:watchdog": "node ./scripts/shared-watchdog.js",
|
|
55
|
-
"background:install": "powershell.exe -NoProfile -ExecutionPolicy Bypass -File ./scripts/install-background-tasks.ps1",
|
|
56
|
-
"background:uninstall": "powershell.exe -NoProfile -ExecutionPolicy Bypass -File ./scripts/uninstall-background-tasks.ps1",
|
|
57
|
-
"channel:send-file": "node ./bin/codeksei.js channel send-file",
|
|
58
|
-
"note:auto": "node ./bin/codeksei.js note auto",
|
|
59
|
-
"note:maybe": "node ./bin/codeksei.js note maybe",
|
|
60
|
-
"note:sync": "node ./bin/codeksei.js note sync",
|
|
61
|
-
"project:radar": "node ./bin/codeksei.js project radar",
|
|
62
|
-
"review:nightly": "node ./bin/codeksei.js review nightly",
|
|
63
|
-
"review:weekly": "node ./bin/codeksei.js review weekly",
|
|
64
|
-
"review:monthly": "node ./bin/codeksei.js review monthly",
|
|
65
|
-
"reminder:write": "node ./bin/codeksei.js reminder write",
|
|
66
|
-
"diary:write": "node ./bin/codeksei.js diary write",
|
|
67
|
-
"system:send": "node ./bin/codeksei.js system send",
|
|
68
|
-
"system:checkin": "node ./bin/codeksei.js system checkin-poller",
|
|
69
|
-
"timeline:event": "node ./bin/codeksei.js timeline event",
|
|
70
|
-
"timeline:write": "node ./bin/codeksei.js timeline write",
|
|
71
|
-
"timeline:read": "node ./bin/codeksei.js timeline read",
|
|
72
|
-
"timeline:categories": "node ./bin/codeksei.js timeline categories",
|
|
73
|
-
"timeline:proposals": "node ./bin/codeksei.js timeline proposals",
|
|
74
|
-
"timeline:build": "node ./bin/codeksei.js timeline build",
|
|
75
|
-
"timeline:serve": "node ./bin/codeksei.js timeline serve",
|
|
76
|
-
"timeline:dev": "node ./bin/codeksei.js timeline dev",
|
|
77
|
-
"timeline:screenshot": "node ./bin/codeksei.js timeline screenshot",
|
|
78
|
-
"check": "node --check ./src/index.js && node --check ./src/core/config.js && node --check ./src/core/app.js && node --check ./src/core/default-targets.js && node --check ./src/core/thread-state-store.js && node --check ./src/core/stream-delivery.js && node --check ./src/core/command-registry.js && node --check ./src/core/system-message-queue-store.js && node --check ./src/core/system-message-dispatcher.js && node --check ./src/core/timeline-screenshot-queue-store.js && node --check ./src/core/workspace-alias.js && node --check ./src/core/shared-bridge-heartbeat.js && node --check ./src/core/workspace-bootstrap.js && node --check ./src/core/project-radar.js && node --check ./src/core/note-sync.js && node --check ./src/core/durable-note-schema.js && node --check ./src/core/review.js && node --check ./src/core/review-semantic.js && node --check ./src/app/channel-send-file-cli.js && node --check ./src/app/note-auto-cli.js && node --check ./src/app/note-sync-cli.js && node --check ./src/app/project-radar-cli.js && node --check ./src/app/review-cli.js && node --check ./src/app/diary-write-cli.js && node --check ./src/app/reminder-write-cli.js && node --check ./src/app/system-send-cli.js && node --check ./src/app/system-checkin-poller.js && node --check ./src/app/timeline-event-cli.js && node --check ./src/app/timeline-screenshot-cli.js && node --check ./src/adapters/channel/weixin/index.js && node --check ./src/adapters/channel/weixin/legacy.js && node --check ./src/adapters/channel/weixin/api.js && node --check ./src/adapters/channel/weixin/api-v2.js && node --check ./src/adapters/channel/weixin/protocol.js && node --check ./src/adapters/channel/weixin/login-common.js && node --check ./src/adapters/channel/weixin/login-legacy.js && node --check ./src/adapters/channel/weixin/login-v2.js && node --check ./src/adapters/channel/weixin/account-store.js && node --check ./src/adapters/channel/weixin/context-token-store.js && node --check ./src/adapters/channel/weixin/message-utils.js && node --check ./src/adapters/channel/weixin/message-utils-v2.js && node --check ./src/adapters/channel/weixin/sync-buffer-store.js && node --check ./src/adapters/channel/weixin/media-mime.js && node --check ./src/adapters/channel/weixin/media-send.js && node --check ./src/adapters/channel/weixin/redact.js && node --check ./src/adapters/channel/weixin/reminder-queue-store.js && node --check ./src/adapters/runtime/codex/index.js && node --check ./src/adapters/runtime/codex/events.js && node --check ./src/adapters/runtime/codex/model-catalog.js && node --check ./src/adapters/runtime/codex/message-utils.js && node --check ./src/adapters/runtime/codex/rpc-client.js && node --check ./src/adapters/runtime/codex/session-store.js && node --check ./src/integrations/timeline/index.js && node --check ./scripts/shared-common.js && node --check ./scripts/shared-start.js && node --check ./scripts/shared-open.js && node --check ./scripts/shared-status.js && node --check ./scripts/shared-supervisor.js && node --check ./scripts/shared-watchdog.js"
|
|
79
|
-
},
|
|
80
|
-
"dependencies": {
|
|
81
|
-
"dotenv": "^16.4.7",
|
|
82
|
-
"qrcode-terminal": "0.12.0",
|
|
83
|
-
"timeline-for-agent": "github:WenXiaoWendy/timeline-for-agent#main",
|
|
84
|
-
"ws": "^8.19.0"
|
|
85
|
-
}
|
|
86
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "codeksei",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Local-first life-assistant agent bridge for Codex, WeChat, timeline, diary, and review workflows.",
|
|
5
|
+
"license": "AGPL-3.0-only",
|
|
6
|
+
"private": false,
|
|
7
|
+
"type": "commonjs",
|
|
8
|
+
"main": "src/index.js",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/Sapientropic/codeksei.git"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://github.com/Sapientropic/codeksei#readme",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/Sapientropic/codeksei/issues"
|
|
16
|
+
},
|
|
17
|
+
"bin": {
|
|
18
|
+
"codeksei": "bin/codeksei.js",
|
|
19
|
+
"cyberboss": "bin/cyberboss.js"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"bin",
|
|
23
|
+
"src",
|
|
24
|
+
"scripts",
|
|
25
|
+
"templates",
|
|
26
|
+
"README.en.md"
|
|
27
|
+
],
|
|
28
|
+
"keywords": [
|
|
29
|
+
"codeksei",
|
|
30
|
+
"codex",
|
|
31
|
+
"wechat",
|
|
32
|
+
"weixin",
|
|
33
|
+
"timeline",
|
|
34
|
+
"review",
|
|
35
|
+
"life-assistant"
|
|
36
|
+
],
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=22"
|
|
39
|
+
},
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"start": "node ./bin/codeksei.js start",
|
|
45
|
+
"start:checkin": "node ./bin/codeksei.js start --checkin",
|
|
46
|
+
"login": "node ./bin/codeksei.js login",
|
|
47
|
+
"accounts": "node ./bin/codeksei.js accounts",
|
|
48
|
+
"doctor": "node ./bin/codeksei.js doctor",
|
|
49
|
+
"help": "node ./bin/codeksei.js help",
|
|
50
|
+
"shared:start": "node ./scripts/shared-start.js",
|
|
51
|
+
"shared:open": "node ./scripts/shared-open.js",
|
|
52
|
+
"shared:status": "node ./scripts/shared-status.js",
|
|
53
|
+
"shared:supervisor": "node ./scripts/shared-supervisor.js",
|
|
54
|
+
"shared:watchdog": "node ./scripts/shared-watchdog.js",
|
|
55
|
+
"background:install": "powershell.exe -NoProfile -ExecutionPolicy Bypass -File ./scripts/install-background-tasks.ps1",
|
|
56
|
+
"background:uninstall": "powershell.exe -NoProfile -ExecutionPolicy Bypass -File ./scripts/uninstall-background-tasks.ps1",
|
|
57
|
+
"channel:send-file": "node ./bin/codeksei.js channel send-file",
|
|
58
|
+
"note:auto": "node ./bin/codeksei.js note auto",
|
|
59
|
+
"note:maybe": "node ./bin/codeksei.js note maybe",
|
|
60
|
+
"note:sync": "node ./bin/codeksei.js note sync",
|
|
61
|
+
"project:radar": "node ./bin/codeksei.js project radar",
|
|
62
|
+
"review:nightly": "node ./bin/codeksei.js review nightly",
|
|
63
|
+
"review:weekly": "node ./bin/codeksei.js review weekly",
|
|
64
|
+
"review:monthly": "node ./bin/codeksei.js review monthly",
|
|
65
|
+
"reminder:write": "node ./bin/codeksei.js reminder write",
|
|
66
|
+
"diary:write": "node ./bin/codeksei.js diary write",
|
|
67
|
+
"system:send": "node ./bin/codeksei.js system send",
|
|
68
|
+
"system:checkin": "node ./bin/codeksei.js system checkin-poller",
|
|
69
|
+
"timeline:event": "node ./bin/codeksei.js timeline event",
|
|
70
|
+
"timeline:write": "node ./bin/codeksei.js timeline write",
|
|
71
|
+
"timeline:read": "node ./bin/codeksei.js timeline read",
|
|
72
|
+
"timeline:categories": "node ./bin/codeksei.js timeline categories",
|
|
73
|
+
"timeline:proposals": "node ./bin/codeksei.js timeline proposals",
|
|
74
|
+
"timeline:build": "node ./bin/codeksei.js timeline build",
|
|
75
|
+
"timeline:serve": "node ./bin/codeksei.js timeline serve",
|
|
76
|
+
"timeline:dev": "node ./bin/codeksei.js timeline dev",
|
|
77
|
+
"timeline:screenshot": "node ./bin/codeksei.js timeline screenshot",
|
|
78
|
+
"check": "node --check ./src/index.js && node --check ./src/core/config.js && node --check ./src/core/timezone.js && node --check ./src/core/app.js && node --check ./src/core/default-targets.js && node --check ./src/core/thread-state-store.js && node --check ./src/core/stream-delivery.js && node --check ./src/core/command-registry.js && node --check ./src/core/system-message-queue-store.js && node --check ./src/core/system-message-dispatcher.js && node --check ./src/core/timeline-screenshot-queue-store.js && node --check ./src/core/workspace-alias.js && node --check ./src/core/shared-bridge-heartbeat.js && node --check ./src/core/workspace-bootstrap.js && node --check ./src/core/project-radar.js && node --check ./src/core/note-sync.js && node --check ./src/core/durable-note-schema.js && node --check ./src/core/review.js && node --check ./src/core/review-semantic.js && node --check ./src/app/channel-send-file-cli.js && node --check ./src/app/note-auto-cli.js && node --check ./src/app/note-sync-cli.js && node --check ./src/app/project-radar-cli.js && node --check ./src/app/review-cli.js && node --check ./src/app/diary-write-cli.js && node --check ./src/app/reminder-write-cli.js && node --check ./src/app/system-send-cli.js && node --check ./src/app/system-checkin-poller.js && node --check ./src/app/timeline-event-cli.js && node --check ./src/app/timeline-screenshot-cli.js && node --check ./src/adapters/channel/weixin/index.js && node --check ./src/adapters/channel/weixin/legacy.js && node --check ./src/adapters/channel/weixin/api.js && node --check ./src/adapters/channel/weixin/api-v2.js && node --check ./src/adapters/channel/weixin/protocol.js && node --check ./src/adapters/channel/weixin/login-common.js && node --check ./src/adapters/channel/weixin/login-legacy.js && node --check ./src/adapters/channel/weixin/login-v2.js && node --check ./src/adapters/channel/weixin/account-store.js && node --check ./src/adapters/channel/weixin/context-token-store.js && node --check ./src/adapters/channel/weixin/message-utils.js && node --check ./src/adapters/channel/weixin/message-utils-v2.js && node --check ./src/adapters/channel/weixin/sync-buffer-store.js && node --check ./src/adapters/channel/weixin/media-mime.js && node --check ./src/adapters/channel/weixin/media-send.js && node --check ./src/adapters/channel/weixin/redact.js && node --check ./src/adapters/channel/weixin/reminder-queue-store.js && node --check ./src/adapters/runtime/codex/index.js && node --check ./src/adapters/runtime/codex/events.js && node --check ./src/adapters/runtime/codex/model-catalog.js && node --check ./src/adapters/runtime/codex/message-utils.js && node --check ./src/adapters/runtime/codex/rpc-client.js && node --check ./src/adapters/runtime/codex/session-store.js && node --check ./src/integrations/timeline/index.js && node --check ./src/integrations/timeline/state-sync.js && node --check ./scripts/shared-common.js && node --check ./scripts/shared-start.js && node --check ./scripts/shared-open.js && node --check ./scripts/shared-status.js && node --check ./scripts/shared-supervisor.js && node --check ./scripts/shared-watchdog.js"
|
|
79
|
+
},
|
|
80
|
+
"dependencies": {
|
|
81
|
+
"dotenv": "^16.4.7",
|
|
82
|
+
"qrcode-terminal": "0.12.0",
|
|
83
|
+
"timeline-for-agent": "github:WenXiaoWendy/timeline-for-agent#main",
|
|
84
|
+
"ws": "^8.19.0"
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
#!/bin/zsh
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
1
|
+
#!/bin/zsh
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
5
5
|
PORT="${CODEKSEI_SHARED_PORT:-${CYBERBOSS_SHARED_PORT:-8765}}"
|
|
6
6
|
REMOTE_URL="ws://127.0.0.1:${PORT}"
|
|
7
7
|
STATE_DIR="${CODEKSEI_STATE_DIR:-${CYBERBOSS_STATE_DIR:-$HOME/.codeksei}}"
|
|
@@ -10,83 +10,83 @@ if [[ ! -d "${STATE_DIR}" && -d "$HOME/.cyberboss" ]]; then
|
|
|
10
10
|
fi
|
|
11
11
|
LOG_DIR="${STATE_DIR}/logs"
|
|
12
12
|
PID_FILE="${LOG_DIR}/shared-wechat.pid"
|
|
13
|
-
|
|
14
|
-
mkdir -p "${LOG_DIR}"
|
|
15
|
-
|
|
16
|
-
function resolve_pid_cwd() {
|
|
17
|
-
local pid="$1"
|
|
18
|
-
lsof -a -p "${pid}" -d cwd -Fn 2>/dev/null | sed -n 's/^n//p' | head -n 1
|
|
19
|
-
}
|
|
20
|
-
|
|
13
|
+
|
|
14
|
+
mkdir -p "${LOG_DIR}"
|
|
15
|
+
|
|
16
|
+
function resolve_pid_cwd() {
|
|
17
|
+
local pid="$1"
|
|
18
|
+
lsof -a -p "${pid}" -d cwd -Fn 2>/dev/null | sed -n 's/^n//p' | head -n 1
|
|
19
|
+
}
|
|
20
|
+
|
|
21
21
|
function list_bridge_processes() {
|
|
22
22
|
ps -ax -o pid=,ppid=,command= | awk '/node \.\/bin\/(codeksei|cyberboss)\.js start --checkin/ { print }'
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
function find_bridge_child_pid() {
|
|
26
|
-
local parent_pid="$1"
|
|
27
|
-
list_bridge_processes | awk -v target_ppid="${parent_pid}" '$2 == target_ppid { print $1; exit }'
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function resolve_bridge_pid() {
|
|
31
|
-
local candidate_pid="$1"
|
|
32
|
-
[[ -n "${candidate_pid}" ]] || return 1
|
|
33
|
-
if ! kill -0 "${candidate_pid}" 2>/dev/null; then
|
|
34
|
-
return 1
|
|
35
|
-
fi
|
|
36
|
-
|
|
37
|
-
local child_pid
|
|
38
|
-
child_pid="$(find_bridge_child_pid "${candidate_pid}")"
|
|
39
|
-
if [[ -n "${child_pid}" ]]; then
|
|
40
|
-
echo "${child_pid}"
|
|
41
|
-
return 0
|
|
42
|
-
fi
|
|
43
|
-
|
|
44
|
-
if [[ "$(resolve_pid_cwd "${candidate_pid}")" == "${ROOT_DIR}" ]]; then
|
|
45
|
-
echo "${candidate_pid}"
|
|
46
|
-
return 0
|
|
47
|
-
fi
|
|
48
|
-
|
|
49
|
-
return 1
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function find_existing_bridge_pid() {
|
|
53
|
-
if [[ -f "${PID_FILE}" ]]; then
|
|
54
|
-
local pid_from_file
|
|
55
|
-
pid_from_file="$(cat "${PID_FILE}" 2>/dev/null || true)"
|
|
56
|
-
local resolved_from_file
|
|
57
|
-
resolved_from_file="$(resolve_bridge_pid "${pid_from_file}" || true)"
|
|
58
|
-
if [[ -n "${resolved_from_file}" ]]; then
|
|
59
|
-
echo "${resolved_from_file}"
|
|
60
|
-
return 0
|
|
61
|
-
fi
|
|
62
|
-
fi
|
|
63
|
-
|
|
64
|
-
local pid
|
|
65
|
-
while read -r pid _; do
|
|
66
|
-
[[ -n "${pid}" ]] || continue
|
|
67
|
-
if [[ "$(resolve_pid_cwd "${pid}")" == "${ROOT_DIR}" ]]; then
|
|
68
|
-
echo "${pid}"
|
|
69
|
-
return 0
|
|
70
|
-
fi
|
|
71
|
-
done < <(list_bridge_processes)
|
|
72
|
-
|
|
73
|
-
return 1
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
"${ROOT_DIR}/scripts/start_shared_app_server.sh"
|
|
77
|
-
|
|
78
|
-
EXISTING_PID="$(find_existing_bridge_pid || true)"
|
|
79
|
-
|
|
80
|
-
if [[ -z "${EXISTING_PID}" ]]; then
|
|
24
|
+
|
|
25
|
+
function find_bridge_child_pid() {
|
|
26
|
+
local parent_pid="$1"
|
|
27
|
+
list_bridge_processes | awk -v target_ppid="${parent_pid}" '$2 == target_ppid { print $1; exit }'
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function resolve_bridge_pid() {
|
|
31
|
+
local candidate_pid="$1"
|
|
32
|
+
[[ -n "${candidate_pid}" ]] || return 1
|
|
33
|
+
if ! kill -0 "${candidate_pid}" 2>/dev/null; then
|
|
34
|
+
return 1
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
local child_pid
|
|
38
|
+
child_pid="$(find_bridge_child_pid "${candidate_pid}")"
|
|
39
|
+
if [[ -n "${child_pid}" ]]; then
|
|
40
|
+
echo "${child_pid}"
|
|
41
|
+
return 0
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
if [[ "$(resolve_pid_cwd "${candidate_pid}")" == "${ROOT_DIR}" ]]; then
|
|
45
|
+
echo "${candidate_pid}"
|
|
46
|
+
return 0
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
return 1
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function find_existing_bridge_pid() {
|
|
53
|
+
if [[ -f "${PID_FILE}" ]]; then
|
|
54
|
+
local pid_from_file
|
|
55
|
+
pid_from_file="$(cat "${PID_FILE}" 2>/dev/null || true)"
|
|
56
|
+
local resolved_from_file
|
|
57
|
+
resolved_from_file="$(resolve_bridge_pid "${pid_from_file}" || true)"
|
|
58
|
+
if [[ -n "${resolved_from_file}" ]]; then
|
|
59
|
+
echo "${resolved_from_file}"
|
|
60
|
+
return 0
|
|
61
|
+
fi
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
local pid
|
|
65
|
+
while read -r pid _; do
|
|
66
|
+
[[ -n "${pid}" ]] || continue
|
|
67
|
+
if [[ "$(resolve_pid_cwd "${pid}")" == "${ROOT_DIR}" ]]; then
|
|
68
|
+
echo "${pid}"
|
|
69
|
+
return 0
|
|
70
|
+
fi
|
|
71
|
+
done < <(list_bridge_processes)
|
|
72
|
+
|
|
73
|
+
return 1
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
"${ROOT_DIR}/scripts/start_shared_app_server.sh"
|
|
77
|
+
|
|
78
|
+
EXISTING_PID="$(find_existing_bridge_pid || true)"
|
|
79
|
+
|
|
80
|
+
if [[ -z "${EXISTING_PID}" ]]; then
|
|
81
81
|
echo "shared codeksei is not running." >&2
|
|
82
|
-
echo "start it in a separate terminal and keep it in the foreground:" >&2
|
|
83
|
-
echo " cd ${ROOT_DIR}" >&2
|
|
84
|
-
echo " ./scripts/start_shared_wechat.sh" >&2
|
|
85
|
-
exit 1
|
|
86
|
-
fi
|
|
87
|
-
|
|
88
|
-
echo "${EXISTING_PID}" > "${PID_FILE}"
|
|
89
|
-
|
|
82
|
+
echo "start it in a separate terminal and keep it in the foreground:" >&2
|
|
83
|
+
echo " cd ${ROOT_DIR}" >&2
|
|
84
|
+
echo " ./scripts/start_shared_wechat.sh" >&2
|
|
85
|
+
exit 1
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
echo "${EXISTING_PID}" > "${PID_FILE}"
|
|
89
|
+
|
|
90
90
|
echo "shared codeksei running pid=${EXISTING_PID} endpoint=${REMOTE_URL}"
|
|
91
91
|
|
|
92
92
|
export CODEKSEI_CODEX_ENDPOINT="${REMOTE_URL}"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#!/bin/zsh
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
1
|
+
#!/bin/zsh
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
4
|
PORT="${CODEKSEI_SHARED_PORT:-${CYBERBOSS_SHARED_PORT:-8765}}"
|
|
5
5
|
REMOTE_URL="${CODEKSEI_CODEX_ENDPOINT:-${CYBERBOSS_CODEX_ENDPOINT:-ws://127.0.0.1:${PORT}}}"
|
|
6
6
|
STATE_DIR="${CODEKSEI_STATE_DIR:-${CYBERBOSS_STATE_DIR:-$HOME/.codeksei}}"
|
|
@@ -9,109 +9,109 @@ if [[ ! -d "${STATE_DIR}" && -d "$HOME/.cyberboss" ]]; then
|
|
|
9
9
|
fi
|
|
10
10
|
SESSION_FILE="${CODEKSEI_SESSIONS_FILE:-${CYBERBOSS_SESSIONS_FILE:-${STATE_DIR}/sessions.json}}"
|
|
11
11
|
WORKSPACE_ROOT="${CODEKSEI_WORKSPACE_ROOT:-${CYBERBOSS_WORKSPACE_ROOT:-$PWD}}"
|
|
12
|
-
ACCOUNT_DIR="${STATE_DIR}/accounts"
|
|
13
|
-
|
|
14
|
-
if [[ ! -f "${SESSION_FILE}" ]]; then
|
|
15
|
-
echo "session file not found: ${SESSION_FILE}" >&2
|
|
16
|
-
exit 1
|
|
17
|
-
fi
|
|
18
|
-
|
|
19
|
-
RESOLVED="$(
|
|
20
|
-
node -e '
|
|
21
|
-
const fs = require("fs");
|
|
22
|
-
const path = require("path");
|
|
23
|
-
|
|
24
|
-
const sessionFile = process.argv[1];
|
|
25
|
-
const workspaceRoot = process.argv[2];
|
|
26
|
-
const accountDir = process.argv[3];
|
|
27
|
-
const data = JSON.parse(fs.readFileSync(sessionFile, "utf8"));
|
|
28
|
-
const bindings = Object.entries(data.bindings || {}).map(([bindingKey, binding]) => ({ bindingKey, ...(binding || {}) }));
|
|
29
|
-
|
|
30
|
-
function normalize(value) {
|
|
31
|
-
return typeof value === "string" ? value.trim() : "";
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function toTimestamp(value) {
|
|
35
|
-
const parsed = Date.parse(normalize(value));
|
|
36
|
-
return Number.isFinite(parsed) ? parsed : 0;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function resolveCurrentAccountId(dir) {
|
|
40
|
-
const normalizedDir = normalize(dir);
|
|
41
|
-
if (!normalizedDir || !fs.existsSync(normalizedDir)) {
|
|
42
|
-
return "";
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const entries = fs.readdirSync(normalizedDir)
|
|
46
|
-
.filter((name) => name.endsWith(".json") && !name.endsWith(".context-tokens.json"))
|
|
47
|
-
.map((name) => {
|
|
48
|
-
const fullPath = path.join(normalizedDir, name);
|
|
49
|
-
try {
|
|
50
|
-
const parsed = JSON.parse(fs.readFileSync(fullPath, "utf8"));
|
|
51
|
-
return {
|
|
52
|
-
accountId: normalize(parsed && parsed.accountId),
|
|
53
|
-
savedAt: toTimestamp(parsed && parsed.savedAt),
|
|
54
|
-
};
|
|
55
|
-
} catch {
|
|
56
|
-
return null;
|
|
57
|
-
}
|
|
58
|
-
})
|
|
59
|
-
.filter(Boolean)
|
|
60
|
-
.filter((entry) => entry.accountId);
|
|
61
|
-
|
|
62
|
-
entries.sort((left, right) => right.savedAt - left.savedAt);
|
|
63
|
-
return entries[0]?.accountId || "";
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function getThreadId(binding, root) {
|
|
67
|
-
const normalizedRoot = normalize(root);
|
|
68
|
-
if (!normalizedRoot) {
|
|
69
|
-
return "";
|
|
70
|
-
}
|
|
71
|
-
const map = binding && typeof binding.threadIdByWorkspaceRoot === "object"
|
|
72
|
-
? binding.threadIdByWorkspaceRoot
|
|
73
|
-
: {};
|
|
74
|
-
return normalize(map[normalizedRoot]);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const normalizedWorkspaceRoot = normalize(workspaceRoot);
|
|
78
|
-
const currentAccountId = resolveCurrentAccountId(accountDir);
|
|
79
|
-
|
|
80
|
-
const filteredBindings = bindings
|
|
81
|
-
.filter((binding) => !currentAccountId || normalize(binding.accountId) === currentAccountId)
|
|
82
|
-
.sort((left, right) => toTimestamp(right.updatedAt) - toTimestamp(left.updatedAt));
|
|
83
|
-
|
|
84
|
-
const exactBinding = filteredBindings.find((binding) => getThreadId(binding, normalizedWorkspaceRoot));
|
|
85
|
-
if (exactBinding) {
|
|
86
|
-
process.stdout.write(`${getThreadId(exactBinding, normalizedWorkspaceRoot)}\n${normalizedWorkspaceRoot}`);
|
|
87
|
-
process.exit(0);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const activeBinding = filteredBindings.find((binding) => {
|
|
91
|
-
const activeWorkspaceRoot = normalize(binding && binding.activeWorkspaceRoot);
|
|
92
|
-
return activeWorkspaceRoot && getThreadId(binding, activeWorkspaceRoot);
|
|
93
|
-
});
|
|
94
|
-
if (activeBinding) {
|
|
95
|
-
const activeWorkspaceRoot = normalize(activeBinding.activeWorkspaceRoot);
|
|
96
|
-
process.stdout.write(`${getThreadId(activeBinding, activeWorkspaceRoot)}\n${activeWorkspaceRoot}`);
|
|
97
|
-
process.exit(0);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
process.exit(1);
|
|
101
|
-
' "${SESSION_FILE}" "${WORKSPACE_ROOT}" "${ACCOUNT_DIR}"
|
|
102
|
-
)"
|
|
103
|
-
|
|
104
|
-
if [[ -z "${RESOLVED}" ]]; then
|
|
105
|
-
echo "no bound WeChat thread found for workspace: ${WORKSPACE_ROOT}" >&2
|
|
106
|
-
exit 1
|
|
107
|
-
fi
|
|
108
|
-
|
|
109
|
-
THREAD_ID="${RESOLVED%%$'\n'*}"
|
|
110
|
-
RESOLVED_WORKSPACE_ROOT="${RESOLVED#*$'\n'}"
|
|
111
|
-
|
|
112
|
-
if [[ -z "${THREAD_ID}" || -z "${RESOLVED_WORKSPACE_ROOT}" ]]; then
|
|
113
|
-
echo "failed to resolve bound WeChat thread from: ${SESSION_FILE}" >&2
|
|
114
|
-
exit 1
|
|
115
|
-
fi
|
|
116
|
-
|
|
12
|
+
ACCOUNT_DIR="${STATE_DIR}/accounts"
|
|
13
|
+
|
|
14
|
+
if [[ ! -f "${SESSION_FILE}" ]]; then
|
|
15
|
+
echo "session file not found: ${SESSION_FILE}" >&2
|
|
16
|
+
exit 1
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
RESOLVED="$(
|
|
20
|
+
node -e '
|
|
21
|
+
const fs = require("fs");
|
|
22
|
+
const path = require("path");
|
|
23
|
+
|
|
24
|
+
const sessionFile = process.argv[1];
|
|
25
|
+
const workspaceRoot = process.argv[2];
|
|
26
|
+
const accountDir = process.argv[3];
|
|
27
|
+
const data = JSON.parse(fs.readFileSync(sessionFile, "utf8"));
|
|
28
|
+
const bindings = Object.entries(data.bindings || {}).map(([bindingKey, binding]) => ({ bindingKey, ...(binding || {}) }));
|
|
29
|
+
|
|
30
|
+
function normalize(value) {
|
|
31
|
+
return typeof value === "string" ? value.trim() : "";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function toTimestamp(value) {
|
|
35
|
+
const parsed = Date.parse(normalize(value));
|
|
36
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function resolveCurrentAccountId(dir) {
|
|
40
|
+
const normalizedDir = normalize(dir);
|
|
41
|
+
if (!normalizedDir || !fs.existsSync(normalizedDir)) {
|
|
42
|
+
return "";
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const entries = fs.readdirSync(normalizedDir)
|
|
46
|
+
.filter((name) => name.endsWith(".json") && !name.endsWith(".context-tokens.json"))
|
|
47
|
+
.map((name) => {
|
|
48
|
+
const fullPath = path.join(normalizedDir, name);
|
|
49
|
+
try {
|
|
50
|
+
const parsed = JSON.parse(fs.readFileSync(fullPath, "utf8"));
|
|
51
|
+
return {
|
|
52
|
+
accountId: normalize(parsed && parsed.accountId),
|
|
53
|
+
savedAt: toTimestamp(parsed && parsed.savedAt),
|
|
54
|
+
};
|
|
55
|
+
} catch {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
.filter(Boolean)
|
|
60
|
+
.filter((entry) => entry.accountId);
|
|
61
|
+
|
|
62
|
+
entries.sort((left, right) => right.savedAt - left.savedAt);
|
|
63
|
+
return entries[0]?.accountId || "";
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function getThreadId(binding, root) {
|
|
67
|
+
const normalizedRoot = normalize(root);
|
|
68
|
+
if (!normalizedRoot) {
|
|
69
|
+
return "";
|
|
70
|
+
}
|
|
71
|
+
const map = binding && typeof binding.threadIdByWorkspaceRoot === "object"
|
|
72
|
+
? binding.threadIdByWorkspaceRoot
|
|
73
|
+
: {};
|
|
74
|
+
return normalize(map[normalizedRoot]);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const normalizedWorkspaceRoot = normalize(workspaceRoot);
|
|
78
|
+
const currentAccountId = resolveCurrentAccountId(accountDir);
|
|
79
|
+
|
|
80
|
+
const filteredBindings = bindings
|
|
81
|
+
.filter((binding) => !currentAccountId || normalize(binding.accountId) === currentAccountId)
|
|
82
|
+
.sort((left, right) => toTimestamp(right.updatedAt) - toTimestamp(left.updatedAt));
|
|
83
|
+
|
|
84
|
+
const exactBinding = filteredBindings.find((binding) => getThreadId(binding, normalizedWorkspaceRoot));
|
|
85
|
+
if (exactBinding) {
|
|
86
|
+
process.stdout.write(`${getThreadId(exactBinding, normalizedWorkspaceRoot)}\n${normalizedWorkspaceRoot}`);
|
|
87
|
+
process.exit(0);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const activeBinding = filteredBindings.find((binding) => {
|
|
91
|
+
const activeWorkspaceRoot = normalize(binding && binding.activeWorkspaceRoot);
|
|
92
|
+
return activeWorkspaceRoot && getThreadId(binding, activeWorkspaceRoot);
|
|
93
|
+
});
|
|
94
|
+
if (activeBinding) {
|
|
95
|
+
const activeWorkspaceRoot = normalize(activeBinding.activeWorkspaceRoot);
|
|
96
|
+
process.stdout.write(`${getThreadId(activeBinding, activeWorkspaceRoot)}\n${activeWorkspaceRoot}`);
|
|
97
|
+
process.exit(0);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
process.exit(1);
|
|
101
|
+
' "${SESSION_FILE}" "${WORKSPACE_ROOT}" "${ACCOUNT_DIR}"
|
|
102
|
+
)"
|
|
103
|
+
|
|
104
|
+
if [[ -z "${RESOLVED}" ]]; then
|
|
105
|
+
echo "no bound WeChat thread found for workspace: ${WORKSPACE_ROOT}" >&2
|
|
106
|
+
exit 1
|
|
107
|
+
fi
|
|
108
|
+
|
|
109
|
+
THREAD_ID="${RESOLVED%%$'\n'*}"
|
|
110
|
+
RESOLVED_WORKSPACE_ROOT="${RESOLVED#*$'\n'}"
|
|
111
|
+
|
|
112
|
+
if [[ -z "${THREAD_ID}" || -z "${RESOLVED_WORKSPACE_ROOT}" ]]; then
|
|
113
|
+
echo "failed to resolve bound WeChat thread from: ${SESSION_FILE}" >&2
|
|
114
|
+
exit 1
|
|
115
|
+
fi
|
|
116
|
+
|
|
117
117
|
exec codex resume "${THREAD_ID}" --remote "${REMOTE_URL}" -C "${RESOLVED_WORKSPACE_ROOT}" "$@"
|