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/scripts/shared-common.js
CHANGED
|
@@ -72,34 +72,34 @@ function loadSharedEnv() {
|
|
|
72
72
|
function ensureLogDir() {
|
|
73
73
|
fs.mkdirSync(logDir, { recursive: true });
|
|
74
74
|
}
|
|
75
|
-
|
|
76
|
-
function isPidAlive(pid) {
|
|
77
|
-
const numeric = Number(pid);
|
|
78
|
-
if (!Number.isInteger(numeric) || numeric <= 0) {
|
|
79
|
-
return false;
|
|
80
|
-
}
|
|
81
|
-
try {
|
|
82
|
-
process.kill(numeric, 0);
|
|
83
|
-
return true;
|
|
84
|
-
} catch {
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function readPidFile(filePath) {
|
|
90
|
-
try {
|
|
91
|
-
const raw = fs.readFileSync(filePath, "utf8").trim();
|
|
92
|
-
return raw ? Number.parseInt(raw, 10) : 0;
|
|
93
|
-
} catch {
|
|
94
|
-
return 0;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function writePidFile(filePath, pid) {
|
|
99
|
-
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
100
|
-
fs.writeFileSync(filePath, `${pid}\n`, "utf8");
|
|
101
|
-
}
|
|
102
|
-
|
|
75
|
+
|
|
76
|
+
function isPidAlive(pid) {
|
|
77
|
+
const numeric = Number(pid);
|
|
78
|
+
if (!Number.isInteger(numeric) || numeric <= 0) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
process.kill(numeric, 0);
|
|
83
|
+
return true;
|
|
84
|
+
} catch {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function readPidFile(filePath) {
|
|
90
|
+
try {
|
|
91
|
+
const raw = fs.readFileSync(filePath, "utf8").trim();
|
|
92
|
+
return raw ? Number.parseInt(raw, 10) : 0;
|
|
93
|
+
} catch {
|
|
94
|
+
return 0;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function writePidFile(filePath, pid) {
|
|
99
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
100
|
+
fs.writeFileSync(filePath, `${pid}\n`, "utf8");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
103
|
function removePidFileIfMatches(filePath, pid) {
|
|
104
104
|
const current = readPidFile(filePath);
|
|
105
105
|
if (current && current === pid) {
|
|
@@ -164,26 +164,26 @@ function findListeningPidByPort(targetPort) {
|
|
|
164
164
|
return 0;
|
|
165
165
|
}
|
|
166
166
|
}
|
|
167
|
-
|
|
167
|
+
|
|
168
168
|
function checkReadyz() {
|
|
169
169
|
return new Promise((resolve) => {
|
|
170
|
-
const req = http.get(
|
|
171
|
-
{
|
|
172
|
-
hostname: "127.0.0.1",
|
|
173
|
-
port: Number(port),
|
|
174
|
-
path: "/readyz",
|
|
175
|
-
timeout: 500,
|
|
176
|
-
},
|
|
177
|
-
(res) => {
|
|
178
|
-
res.resume();
|
|
179
|
-
resolve(res.statusCode >= 200 && res.statusCode < 300);
|
|
180
|
-
}
|
|
181
|
-
);
|
|
182
|
-
req.on("error", () => resolve(false));
|
|
183
|
-
req.on("timeout", () => {
|
|
184
|
-
req.destroy();
|
|
185
|
-
resolve(false);
|
|
186
|
-
});
|
|
170
|
+
const req = http.get(
|
|
171
|
+
{
|
|
172
|
+
hostname: "127.0.0.1",
|
|
173
|
+
port: Number(port),
|
|
174
|
+
path: "/readyz",
|
|
175
|
+
timeout: 500,
|
|
176
|
+
},
|
|
177
|
+
(res) => {
|
|
178
|
+
res.resume();
|
|
179
|
+
resolve(res.statusCode >= 200 && res.statusCode < 300);
|
|
180
|
+
}
|
|
181
|
+
);
|
|
182
|
+
req.on("error", () => resolve(false));
|
|
183
|
+
req.on("timeout", () => {
|
|
184
|
+
req.destroy();
|
|
185
|
+
resolve(false);
|
|
186
|
+
});
|
|
187
187
|
});
|
|
188
188
|
}
|
|
189
189
|
|
|
@@ -206,17 +206,17 @@ async function resolveReadyAppServerPid() {
|
|
|
206
206
|
|
|
207
207
|
return pidFromFile && isPidAlive(pidFromFile) ? pidFromFile : 0;
|
|
208
208
|
}
|
|
209
|
-
|
|
210
|
-
async function waitForReadyz({ attempts = 10, delayMs = 300 } = {}) {
|
|
211
|
-
for (let index = 0; index < attempts; index += 1) {
|
|
212
|
-
if (await checkReadyz()) {
|
|
213
|
-
return true;
|
|
214
|
-
}
|
|
215
|
-
await sleep(delayMs);
|
|
216
|
-
}
|
|
217
|
-
return false;
|
|
218
|
-
}
|
|
219
|
-
|
|
209
|
+
|
|
210
|
+
async function waitForReadyz({ attempts = 10, delayMs = 300 } = {}) {
|
|
211
|
+
for (let index = 0; index < attempts; index += 1) {
|
|
212
|
+
if (await checkReadyz()) {
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
await sleep(delayMs);
|
|
216
|
+
}
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
220
|
function openLogFile(filePath) {
|
|
221
221
|
return fs.openSync(filePath, "a");
|
|
222
222
|
}
|
|
@@ -558,8 +558,8 @@ async function ensureSharedAppServer() {
|
|
|
558
558
|
logFile: appServerLogFile,
|
|
559
559
|
env,
|
|
560
560
|
});
|
|
561
|
-
writePidFile(appServerPidFile, pid);
|
|
562
|
-
|
|
561
|
+
writePidFile(appServerPidFile, pid);
|
|
562
|
+
|
|
563
563
|
const ready = await waitForReadyz();
|
|
564
564
|
if (!ready) {
|
|
565
565
|
throw new Error(`failed to start shared app-server; check ${appServerLogFile}`);
|
|
@@ -601,9 +601,9 @@ function ensureBridgeNotRunning() {
|
|
|
601
601
|
const pidFromFile = readPidFile(bridgePidFile);
|
|
602
602
|
if (pidFromFile && isPidAlive(pidFromFile)) {
|
|
603
603
|
return pidFromFile;
|
|
604
|
-
}
|
|
605
|
-
if (pidFromFile) {
|
|
606
|
-
fs.rmSync(bridgePidFile, { force: true });
|
|
604
|
+
}
|
|
605
|
+
if (pidFromFile) {
|
|
606
|
+
fs.rmSync(bridgePidFile, { force: true });
|
|
607
607
|
}
|
|
608
608
|
return 0;
|
|
609
609
|
}
|
|
@@ -669,88 +669,88 @@ async function ensureManagedSupervisor({ intervalMinutes = 5 } = {}) {
|
|
|
669
669
|
status: "started",
|
|
670
670
|
};
|
|
671
671
|
}
|
|
672
|
-
|
|
673
|
-
function resolveCurrentAccountId() {
|
|
674
|
-
if (!fs.existsSync(accountsDir)) {
|
|
675
|
-
return "";
|
|
676
|
-
}
|
|
677
|
-
const entries = fs.readdirSync(accountsDir)
|
|
678
|
-
.filter((name) => name.endsWith(".json") && !name.endsWith(".context-tokens.json"))
|
|
679
|
-
.map((name) => {
|
|
680
|
-
const fullPath = path.join(accountsDir, name);
|
|
681
|
-
try {
|
|
682
|
-
const parsed = JSON.parse(fs.readFileSync(fullPath, "utf8"));
|
|
683
|
-
return {
|
|
684
|
-
accountId: normalizeText(parsed?.accountId),
|
|
685
|
-
savedAt: parseTimestamp(parsed?.savedAt),
|
|
686
|
-
};
|
|
687
|
-
} catch {
|
|
688
|
-
return null;
|
|
689
|
-
}
|
|
690
|
-
})
|
|
691
|
-
.filter(Boolean)
|
|
692
|
-
.filter((entry) => entry.accountId);
|
|
693
|
-
entries.sort((left, right) => right.savedAt - left.savedAt);
|
|
694
|
-
return entries[0]?.accountId || "";
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
function resolveBoundThread(workspaceRoot) {
|
|
698
|
-
if (!fs.existsSync(sessionFile)) {
|
|
699
|
-
throw new Error(`session file not found: ${sessionFile}`);
|
|
700
|
-
}
|
|
701
|
-
const data = JSON.parse(fs.readFileSync(sessionFile, "utf8"));
|
|
702
|
-
const currentAccountId = resolveCurrentAccountId();
|
|
703
|
-
const bindings = Object.values(data.bindings || {})
|
|
704
|
-
.filter((binding) => !currentAccountId || normalizeText(binding?.accountId) === currentAccountId)
|
|
705
|
-
.sort((left, right) => parseTimestamp(right?.updatedAt) - parseTimestamp(left?.updatedAt));
|
|
706
|
-
|
|
707
|
-
const normalizedWorkspaceRoot = normalizeText(workspaceRoot);
|
|
708
|
-
const exact = bindings.find((binding) => getThreadId(binding, normalizedWorkspaceRoot));
|
|
709
|
-
if (exact) {
|
|
710
|
-
return {
|
|
711
|
-
threadId: getThreadId(exact, normalizedWorkspaceRoot),
|
|
712
|
-
workspaceRoot: normalizedWorkspaceRoot,
|
|
713
|
-
};
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
const active = bindings.find((binding) => {
|
|
717
|
-
const activeWorkspaceRoot = normalizeText(binding?.activeWorkspaceRoot);
|
|
718
|
-
return activeWorkspaceRoot && getThreadId(binding, activeWorkspaceRoot);
|
|
719
|
-
});
|
|
720
|
-
if (active) {
|
|
721
|
-
const activeWorkspaceRoot = normalizeText(active.activeWorkspaceRoot);
|
|
722
|
-
return {
|
|
723
|
-
threadId: getThreadId(active, activeWorkspaceRoot),
|
|
724
|
-
workspaceRoot: activeWorkspaceRoot,
|
|
725
|
-
};
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
throw new Error(`no bound WeChat thread found for workspace: ${workspaceRoot}`);
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
function getThreadId(binding, workspaceRoot) {
|
|
732
|
-
if (!workspaceRoot) {
|
|
733
|
-
return "";
|
|
734
|
-
}
|
|
735
|
-
const map = binding && typeof binding.threadIdByWorkspaceRoot === "object"
|
|
736
|
-
? binding.threadIdByWorkspaceRoot
|
|
737
|
-
: {};
|
|
738
|
-
return normalizeText(map[workspaceRoot]);
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
function parseTimestamp(value) {
|
|
742
|
-
const parsed = Date.parse(normalizeText(value));
|
|
743
|
-
return Number.isFinite(parsed) ? parsed : 0;
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
function normalizeText(value) {
|
|
747
|
-
return typeof value === "string" ? value.trim() : "";
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
function sleep(ms) {
|
|
751
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
752
|
-
}
|
|
753
|
-
|
|
672
|
+
|
|
673
|
+
function resolveCurrentAccountId() {
|
|
674
|
+
if (!fs.existsSync(accountsDir)) {
|
|
675
|
+
return "";
|
|
676
|
+
}
|
|
677
|
+
const entries = fs.readdirSync(accountsDir)
|
|
678
|
+
.filter((name) => name.endsWith(".json") && !name.endsWith(".context-tokens.json"))
|
|
679
|
+
.map((name) => {
|
|
680
|
+
const fullPath = path.join(accountsDir, name);
|
|
681
|
+
try {
|
|
682
|
+
const parsed = JSON.parse(fs.readFileSync(fullPath, "utf8"));
|
|
683
|
+
return {
|
|
684
|
+
accountId: normalizeText(parsed?.accountId),
|
|
685
|
+
savedAt: parseTimestamp(parsed?.savedAt),
|
|
686
|
+
};
|
|
687
|
+
} catch {
|
|
688
|
+
return null;
|
|
689
|
+
}
|
|
690
|
+
})
|
|
691
|
+
.filter(Boolean)
|
|
692
|
+
.filter((entry) => entry.accountId);
|
|
693
|
+
entries.sort((left, right) => right.savedAt - left.savedAt);
|
|
694
|
+
return entries[0]?.accountId || "";
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
function resolveBoundThread(workspaceRoot) {
|
|
698
|
+
if (!fs.existsSync(sessionFile)) {
|
|
699
|
+
throw new Error(`session file not found: ${sessionFile}`);
|
|
700
|
+
}
|
|
701
|
+
const data = JSON.parse(fs.readFileSync(sessionFile, "utf8"));
|
|
702
|
+
const currentAccountId = resolveCurrentAccountId();
|
|
703
|
+
const bindings = Object.values(data.bindings || {})
|
|
704
|
+
.filter((binding) => !currentAccountId || normalizeText(binding?.accountId) === currentAccountId)
|
|
705
|
+
.sort((left, right) => parseTimestamp(right?.updatedAt) - parseTimestamp(left?.updatedAt));
|
|
706
|
+
|
|
707
|
+
const normalizedWorkspaceRoot = normalizeText(workspaceRoot);
|
|
708
|
+
const exact = bindings.find((binding) => getThreadId(binding, normalizedWorkspaceRoot));
|
|
709
|
+
if (exact) {
|
|
710
|
+
return {
|
|
711
|
+
threadId: getThreadId(exact, normalizedWorkspaceRoot),
|
|
712
|
+
workspaceRoot: normalizedWorkspaceRoot,
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
const active = bindings.find((binding) => {
|
|
717
|
+
const activeWorkspaceRoot = normalizeText(binding?.activeWorkspaceRoot);
|
|
718
|
+
return activeWorkspaceRoot && getThreadId(binding, activeWorkspaceRoot);
|
|
719
|
+
});
|
|
720
|
+
if (active) {
|
|
721
|
+
const activeWorkspaceRoot = normalizeText(active.activeWorkspaceRoot);
|
|
722
|
+
return {
|
|
723
|
+
threadId: getThreadId(active, activeWorkspaceRoot),
|
|
724
|
+
workspaceRoot: activeWorkspaceRoot,
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
throw new Error(`no bound WeChat thread found for workspace: ${workspaceRoot}`);
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
function getThreadId(binding, workspaceRoot) {
|
|
732
|
+
if (!workspaceRoot) {
|
|
733
|
+
return "";
|
|
734
|
+
}
|
|
735
|
+
const map = binding && typeof binding.threadIdByWorkspaceRoot === "object"
|
|
736
|
+
? binding.threadIdByWorkspaceRoot
|
|
737
|
+
: {};
|
|
738
|
+
return normalizeText(map[workspaceRoot]);
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
function parseTimestamp(value) {
|
|
742
|
+
const parsed = Date.parse(normalizeText(value));
|
|
743
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
function normalizeText(value) {
|
|
747
|
+
return typeof value === "string" ? value.trim() : "";
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
function sleep(ms) {
|
|
751
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
752
|
+
}
|
|
753
|
+
|
|
754
754
|
module.exports = {
|
|
755
755
|
rootDir,
|
|
756
756
|
port,
|
package/scripts/shared-open.js
CHANGED
|
@@ -30,17 +30,17 @@ async function main() {
|
|
|
30
30
|
shell: false,
|
|
31
31
|
windowsHide: true,
|
|
32
32
|
});
|
|
33
|
-
|
|
34
|
-
child.on("exit", (code, signal) => {
|
|
35
|
-
if (signal) {
|
|
36
|
-
process.kill(process.pid, signal);
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
process.exit(code ?? 0);
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
main().catch((error) => {
|
|
44
|
-
console.error(error.message || String(error));
|
|
45
|
-
process.exit(1);
|
|
46
|
-
});
|
|
33
|
+
|
|
34
|
+
child.on("exit", (code, signal) => {
|
|
35
|
+
if (signal) {
|
|
36
|
+
process.kill(process.pid, signal);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
process.exit(code ?? 0);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
main().catch((error) => {
|
|
44
|
+
console.error(error.message || String(error));
|
|
45
|
+
process.exit(1);
|
|
46
|
+
});
|
package/scripts/shared-start.js
CHANGED
|
@@ -34,8 +34,8 @@ async function main() {
|
|
|
34
34
|
const supervisor = await ensureManagedSupervisor({ intervalMinutes: parseIntervalMinutes() });
|
|
35
35
|
console.log(`shared supervisor ${supervisor.status} pid=${supervisor.pid}`);
|
|
36
36
|
}
|
|
37
|
-
|
|
38
|
-
main().catch((error) => {
|
|
39
|
-
console.error(error.message || String(error));
|
|
40
|
-
process.exit(1);
|
|
41
|
-
});
|
|
37
|
+
|
|
38
|
+
main().catch((error) => {
|
|
39
|
+
console.error(error.message || String(error));
|
|
40
|
+
process.exit(1);
|
|
41
|
+
});
|
package/scripts/shared-status.js
CHANGED
|
@@ -34,34 +34,34 @@ function printPidState(label, filePath, fallbackPid = 0) {
|
|
|
34
34
|
if (!pid) {
|
|
35
35
|
console.log(`${label}=missing`);
|
|
36
36
|
return;
|
|
37
|
-
}
|
|
38
|
-
if (!isPidAlive(pid)) {
|
|
39
|
-
console.log(`${label}=stale`);
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
console.log(`${label}=${pid}`);
|
|
43
|
-
}
|
|
44
|
-
|
|
37
|
+
}
|
|
38
|
+
if (!isPidAlive(pid)) {
|
|
39
|
+
console.log(`${label}=stale`);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
console.log(`${label}=${pid}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
45
|
function checkReadyz() {
|
|
46
|
-
return new Promise((resolve) => {
|
|
47
|
-
const req = http.get(
|
|
48
|
-
{
|
|
49
|
-
hostname: "127.0.0.1",
|
|
50
|
-
port: new URL(listenUrl).port,
|
|
51
|
-
path: "/readyz",
|
|
52
|
-
timeout: 600,
|
|
53
|
-
},
|
|
54
|
-
(res) => {
|
|
55
|
-
res.resume();
|
|
56
|
-
resolve(res.statusCode >= 200 && res.statusCode < 300);
|
|
57
|
-
}
|
|
58
|
-
);
|
|
59
|
-
req.on("error", () => resolve(false));
|
|
60
|
-
req.on("timeout", () => {
|
|
61
|
-
req.destroy();
|
|
62
|
-
resolve(false);
|
|
63
|
-
});
|
|
64
|
-
});
|
|
46
|
+
return new Promise((resolve) => {
|
|
47
|
+
const req = http.get(
|
|
48
|
+
{
|
|
49
|
+
hostname: "127.0.0.1",
|
|
50
|
+
port: new URL(listenUrl).port,
|
|
51
|
+
path: "/readyz",
|
|
52
|
+
timeout: 600,
|
|
53
|
+
},
|
|
54
|
+
(res) => {
|
|
55
|
+
res.resume();
|
|
56
|
+
resolve(res.statusCode >= 200 && res.statusCode < 300);
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
req.on("error", () => resolve(false));
|
|
60
|
+
req.on("timeout", () => {
|
|
61
|
+
req.destroy();
|
|
62
|
+
resolve(false);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
function normalizeText(value) {
|
|
@@ -1,53 +1,53 @@
|
|
|
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
|
LISTEN_URL="ws://127.0.0.1:${PORT}"
|
|
6
6
|
STATE_DIR="${CODEKSEI_STATE_DIR:-${CYBERBOSS_STATE_DIR:-$HOME/.codeksei}}"
|
|
7
7
|
if [[ ! -d "${STATE_DIR}" && -d "$HOME/.cyberboss" ]]; then
|
|
8
8
|
STATE_DIR="$HOME/.cyberboss"
|
|
9
9
|
fi
|
|
10
|
-
LOG_DIR="${STATE_DIR}/logs"
|
|
11
|
-
APP_SERVER_PID_FILE="${LOG_DIR}/shared-app-server.pid"
|
|
12
|
-
WECHAT_PID_FILE="${LOG_DIR}/shared-wechat.pid"
|
|
13
|
-
WECHAT_LOG_FILE="${LOG_DIR}/shared-wechat.log"
|
|
14
|
-
|
|
15
|
-
function print_pid_state() {
|
|
16
|
-
local label="$1"
|
|
17
|
-
local pid_file="$2"
|
|
18
|
-
|
|
19
|
-
if [[ -f "${pid_file}" ]]; then
|
|
20
|
-
local pid
|
|
21
|
-
pid="$(cat "${pid_file}" 2>/dev/null || true)"
|
|
22
|
-
if [[ -n "${pid}" ]] && kill -0 "${pid}" 2>/dev/null; then
|
|
23
|
-
echo "${label}=${pid}"
|
|
24
|
-
return
|
|
25
|
-
fi
|
|
26
|
-
echo "${label}=stale"
|
|
27
|
-
return
|
|
28
|
-
fi
|
|
29
|
-
|
|
30
|
-
echo "${label}=missing"
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
echo "listen=${LISTEN_URL}"
|
|
34
|
-
print_pid_state "shared_app_server_pid" "${APP_SERVER_PID_FILE}"
|
|
10
|
+
LOG_DIR="${STATE_DIR}/logs"
|
|
11
|
+
APP_SERVER_PID_FILE="${LOG_DIR}/shared-app-server.pid"
|
|
12
|
+
WECHAT_PID_FILE="${LOG_DIR}/shared-wechat.pid"
|
|
13
|
+
WECHAT_LOG_FILE="${LOG_DIR}/shared-wechat.log"
|
|
14
|
+
|
|
15
|
+
function print_pid_state() {
|
|
16
|
+
local label="$1"
|
|
17
|
+
local pid_file="$2"
|
|
18
|
+
|
|
19
|
+
if [[ -f "${pid_file}" ]]; then
|
|
20
|
+
local pid
|
|
21
|
+
pid="$(cat "${pid_file}" 2>/dev/null || true)"
|
|
22
|
+
if [[ -n "${pid}" ]] && kill -0 "${pid}" 2>/dev/null; then
|
|
23
|
+
echo "${label}=${pid}"
|
|
24
|
+
return
|
|
25
|
+
fi
|
|
26
|
+
echo "${label}=stale"
|
|
27
|
+
return
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
echo "${label}=missing"
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
echo "listen=${LISTEN_URL}"
|
|
34
|
+
print_pid_state "shared_app_server_pid" "${APP_SERVER_PID_FILE}"
|
|
35
35
|
print_pid_state "shared_codeksei_pid" "${WECHAT_PID_FILE}"
|
|
36
36
|
print_pid_state "shared_cyberboss_pid" "${WECHAT_PID_FILE}"
|
|
37
|
-
|
|
38
|
-
if command -v curl >/dev/null 2>&1; then
|
|
39
|
-
if curl -sf "http://127.0.0.1:${PORT}/readyz" >/dev/null; then
|
|
40
|
-
echo "readyz=ok"
|
|
41
|
-
else
|
|
42
|
-
echo "readyz=down"
|
|
43
|
-
fi
|
|
44
|
-
fi
|
|
45
|
-
|
|
46
|
-
if command -v lsof >/dev/null 2>&1; then
|
|
47
|
-
lsof -nP -iTCP:"${PORT}" -sTCP:LISTEN || true
|
|
48
|
-
fi
|
|
49
|
-
|
|
50
|
-
if [[ -f "${WECHAT_LOG_FILE}" ]]; then
|
|
51
|
-
echo "--- ${WECHAT_LOG_FILE} (tail) ---"
|
|
52
|
-
tail -n 20 "${WECHAT_LOG_FILE}" || true
|
|
53
|
-
fi
|
|
37
|
+
|
|
38
|
+
if command -v curl >/dev/null 2>&1; then
|
|
39
|
+
if curl -sf "http://127.0.0.1:${PORT}/readyz" >/dev/null; then
|
|
40
|
+
echo "readyz=ok"
|
|
41
|
+
else
|
|
42
|
+
echo "readyz=down"
|
|
43
|
+
fi
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
if command -v lsof >/dev/null 2>&1; then
|
|
47
|
+
lsof -nP -iTCP:"${PORT}" -sTCP:LISTEN || true
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
if [[ -f "${WECHAT_LOG_FILE}" ]]; then
|
|
51
|
+
echo "--- ${WECHAT_LOG_FILE} (tail) ---"
|
|
52
|
+
tail -n 20 "${WECHAT_LOG_FILE}" || true
|
|
53
|
+
fi
|
|
@@ -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
|
LISTEN_URL="ws://127.0.0.1:${PORT}"
|
|
6
6
|
STATE_DIR="${CODEKSEI_STATE_DIR:-${CYBERBOSS_STATE_DIR:-$HOME/.codeksei}}"
|
|
@@ -8,58 +8,58 @@ if [[ ! -d "${STATE_DIR}" && -d "$HOME/.cyberboss" ]]; then
|
|
|
8
8
|
STATE_DIR="$HOME/.cyberboss"
|
|
9
9
|
fi
|
|
10
10
|
LOG_DIR="${STATE_DIR}/logs"
|
|
11
|
-
PID_FILE="${LOG_DIR}/shared-app-server.pid"
|
|
12
|
-
LOG_FILE="${LOG_DIR}/shared-app-server.log"
|
|
13
|
-
|
|
14
|
-
function lookup_listen_pid() {
|
|
15
|
-
lsof -nP -iTCP:"${PORT}" -sTCP:LISTEN 2>/dev/null \
|
|
16
|
-
| awk 'NR > 1 { print $2; found=1; exit } END { if (!found) exit 0 }'
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
mkdir -p "${LOG_DIR}"
|
|
11
|
+
PID_FILE="${LOG_DIR}/shared-app-server.pid"
|
|
12
|
+
LOG_FILE="${LOG_DIR}/shared-app-server.log"
|
|
13
|
+
|
|
14
|
+
function lookup_listen_pid() {
|
|
15
|
+
lsof -nP -iTCP:"${PORT}" -sTCP:LISTEN 2>/dev/null \
|
|
16
|
+
| awk 'NR > 1 { print $2; found=1; exit } END { if (!found) exit 0 }'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
mkdir -p "${LOG_DIR}"
|
|
20
20
|
export CODEKSEI_STATE_DIR="${STATE_DIR}"
|
|
21
21
|
export CYBERBOSS_STATE_DIR="${STATE_DIR}"
|
|
22
22
|
export TIMELINE_FOR_AGENT_STATE_DIR="${STATE_DIR}"
|
|
23
23
|
if [[ -z "${TIMELINE_FOR_AGENT_CHROME_PATH:-}" ]]; then
|
|
24
24
|
export TIMELINE_FOR_AGENT_CHROME_PATH="${CODEKSEI_SCREENSHOT_CHROME_PATH:-${CYBERBOSS_SCREENSHOT_CHROME_PATH:-/Applications/Google Chrome.app/Contents/MacOS/Google Chrome}}"
|
|
25
25
|
fi
|
|
26
|
-
|
|
27
|
-
if [[ -f "${PID_FILE}" ]]; then
|
|
28
|
-
EXISTING_PID="$(cat "${PID_FILE}")"
|
|
29
|
-
if [[ -n "${EXISTING_PID}" ]] && kill -0 "${EXISTING_PID}" 2>/dev/null; then
|
|
30
|
-
echo "shared app-server already running pid=${EXISTING_PID} listen=${LISTEN_URL}"
|
|
31
|
-
exit 0
|
|
32
|
-
fi
|
|
33
|
-
rm -f "${PID_FILE}"
|
|
34
|
-
fi
|
|
35
|
-
|
|
36
|
-
EXISTING_PID="$(lookup_listen_pid || true)"
|
|
37
|
-
if [[ -n "${EXISTING_PID}" ]]; then
|
|
38
|
-
echo "${EXISTING_PID}" > "${PID_FILE}"
|
|
39
|
-
echo "shared app-server already running pid=${EXISTING_PID} listen=${LISTEN_URL}"
|
|
40
|
-
exit 0
|
|
41
|
-
fi
|
|
42
|
-
|
|
43
|
-
nohup codex app-server --listen "${LISTEN_URL}" >> "${LOG_FILE}" 2>&1 &
|
|
44
|
-
APP_SERVER_PID=$!
|
|
45
|
-
echo "${APP_SERVER_PID}" > "${PID_FILE}"
|
|
46
|
-
sleep 1
|
|
47
|
-
|
|
48
|
-
LISTEN_PID="$(lookup_listen_pid || true)"
|
|
49
|
-
if kill -0 "${APP_SERVER_PID}" 2>/dev/null && [[ -n "${LISTEN_PID}" ]]; then
|
|
50
|
-
echo "${LISTEN_PID}" > "${PID_FILE}"
|
|
51
|
-
echo "started shared app-server pid=${LISTEN_PID} listen=${LISTEN_URL}"
|
|
52
|
-
echo "log=${LOG_FILE}"
|
|
53
|
-
exit 0
|
|
54
|
-
fi
|
|
55
|
-
|
|
56
|
-
EXISTING_PID="$(lookup_listen_pid || true)"
|
|
57
|
-
if [[ -n "${EXISTING_PID}" ]]; then
|
|
58
|
-
echo "${EXISTING_PID}" > "${PID_FILE}"
|
|
59
|
-
echo "shared app-server already running pid=${EXISTING_PID} listen=${LISTEN_URL}"
|
|
60
|
-
exit 0
|
|
61
|
-
fi
|
|
62
|
-
|
|
63
|
-
echo "failed to start shared app-server; check ${LOG_FILE}" >&2
|
|
64
|
-
tail -n 20 "${LOG_FILE}" >&2 || true
|
|
65
|
-
exit 1
|
|
26
|
+
|
|
27
|
+
if [[ -f "${PID_FILE}" ]]; then
|
|
28
|
+
EXISTING_PID="$(cat "${PID_FILE}")"
|
|
29
|
+
if [[ -n "${EXISTING_PID}" ]] && kill -0 "${EXISTING_PID}" 2>/dev/null; then
|
|
30
|
+
echo "shared app-server already running pid=${EXISTING_PID} listen=${LISTEN_URL}"
|
|
31
|
+
exit 0
|
|
32
|
+
fi
|
|
33
|
+
rm -f "${PID_FILE}"
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
EXISTING_PID="$(lookup_listen_pid || true)"
|
|
37
|
+
if [[ -n "${EXISTING_PID}" ]]; then
|
|
38
|
+
echo "${EXISTING_PID}" > "${PID_FILE}"
|
|
39
|
+
echo "shared app-server already running pid=${EXISTING_PID} listen=${LISTEN_URL}"
|
|
40
|
+
exit 0
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
nohup codex app-server --listen "${LISTEN_URL}" >> "${LOG_FILE}" 2>&1 &
|
|
44
|
+
APP_SERVER_PID=$!
|
|
45
|
+
echo "${APP_SERVER_PID}" > "${PID_FILE}"
|
|
46
|
+
sleep 1
|
|
47
|
+
|
|
48
|
+
LISTEN_PID="$(lookup_listen_pid || true)"
|
|
49
|
+
if kill -0 "${APP_SERVER_PID}" 2>/dev/null && [[ -n "${LISTEN_PID}" ]]; then
|
|
50
|
+
echo "${LISTEN_PID}" > "${PID_FILE}"
|
|
51
|
+
echo "started shared app-server pid=${LISTEN_PID} listen=${LISTEN_URL}"
|
|
52
|
+
echo "log=${LOG_FILE}"
|
|
53
|
+
exit 0
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
EXISTING_PID="$(lookup_listen_pid || true)"
|
|
57
|
+
if [[ -n "${EXISTING_PID}" ]]; then
|
|
58
|
+
echo "${EXISTING_PID}" > "${PID_FILE}"
|
|
59
|
+
echo "shared app-server already running pid=${EXISTING_PID} listen=${LISTEN_URL}"
|
|
60
|
+
exit 0
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
echo "failed to start shared app-server; check ${LOG_FILE}" >&2
|
|
64
|
+
tail -n 20 "${LOG_FILE}" >&2 || true
|
|
65
|
+
exit 1
|