@bolloon/bolloon-agent 0.2.9 → 0.2.11
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/README.md +467 -467
- package/bin/bolloon-cli.cjs +183 -183
- package/bin/bolloon.cjs +0 -0
- package/bin/bolloon.js +157 -0
- package/dist/agents/agent-manifest-protocol.js +0 -52
- package/dist/agents/constraint-layer.js +19 -19
- package/dist/agents/pi-sdk.js +287 -1213
- package/dist/agents/shell-guard.js +2 -2
- package/dist/agents/workflow-pivot-loop.js +2 -81
- package/dist/bollharness/src/scripts/deploy-guard.js +8 -8
- package/dist/bollharness-integration/context-router-judgment.js +4 -4
- package/dist/bollharness-integration/context-router.js +292 -292
- package/dist/bollharness-integration/gate-state-machine.js +13 -26
- package/dist/bollharness-integration/integration.js +0 -71
- package/dist/bollharness-integration/llm-judgment-engine.js +134 -134
- package/dist/bollharness-integration/skill-adapter.js +127 -52
- package/dist/bootstrap/context-collector.js +3 -6
- package/dist/bootstrap/lifecycle-hooks.js +1 -15
- package/dist/cli-entry.js +35 -39
- package/dist/constraint-runtime/src/_archive_helper.js +9 -0
- package/dist/constraint-runtime/src/agent/coordinator.js +48 -0
- package/dist/constraint-runtime/src/agent/index.js +1 -0
- package/dist/constraint-runtime/src/assistant/index.js +12 -0
- package/dist/constraint-runtime/src/bootstrap/index.js +12 -0
- package/dist/constraint-runtime/src/bootstrap_graph.js +13 -0
- package/dist/constraint-runtime/src/bridge/index.js +12 -0
- package/dist/constraint-runtime/src/buddy/index.js +12 -0
- package/dist/constraint-runtime/src/cli/index.js +12 -0
- package/dist/constraint-runtime/src/command_graph.js +10 -0
- package/dist/constraint-runtime/src/commands.js +60 -0
- package/dist/constraint-runtime/src/components/index.js +12 -0
- package/dist/constraint-runtime/src/constants/index.js +12 -0
- package/dist/constraint-runtime/src/constraint/budget.js +22 -0
- package/dist/constraint-runtime/src/constraint/index.js +2 -0
- package/dist/constraint-runtime/src/constraint/permission.js +20 -0
- package/dist/constraint-runtime/src/context.js +30 -0
- package/dist/constraint-runtime/src/coordinator/index.js +12 -0
- package/dist/constraint-runtime/src/cost_hook.js +4 -0
- package/dist/constraint-runtime/src/cost_tracker.js +8 -0
- package/dist/constraint-runtime/src/deferred_init.js +10 -0
- package/dist/constraint-runtime/src/direct_modes.js +6 -0
- package/dist/constraint-runtime/src/dynamic-tool-loader.js +85 -0
- package/dist/constraint-runtime/src/entrypoints/index.js +12 -0
- package/dist/constraint-runtime/src/execution_registry.js +44 -0
- package/dist/constraint-runtime/src/history.js +9 -0
- package/dist/constraint-runtime/src/hooks/index.js +12 -0
- package/dist/constraint-runtime/src/index.js +26 -0
- package/dist/constraint-runtime/src/ink.js +4 -0
- package/dist/constraint-runtime/src/keybindings/index.js +12 -0
- package/dist/constraint-runtime/src/memdir/index.js +12 -0
- package/dist/constraint-runtime/src/migrations/index.js +12 -0
- package/dist/constraint-runtime/src/models.js +1 -0
- package/dist/constraint-runtime/src/moreright/index.js +12 -0
- package/dist/constraint-runtime/src/native_ts/index.js +12 -0
- package/dist/constraint-runtime/src/output_styles/index.js +12 -0
- package/dist/constraint-runtime/src/parity_audit.js +12 -0
- package/dist/constraint-runtime/src/plugins/index.js +12 -0
- package/dist/constraint-runtime/src/port_manifest.js +11 -0
- package/dist/constraint-runtime/src/prefetch.js +9 -0
- package/dist/constraint-runtime/src/query.js +1 -0
- package/dist/constraint-runtime/src/remote/index.js +12 -0
- package/dist/constraint-runtime/src/remote_runtime.js +9 -0
- package/dist/constraint-runtime/src/runtime/index.js +1 -0
- package/dist/constraint-runtime/src/runtime/session.js +35 -0
- package/dist/constraint-runtime/src/schemas/index.js +12 -0
- package/dist/constraint-runtime/src/screens/index.js +12 -0
- package/dist/constraint-runtime/src/server/index.js +12 -0
- package/dist/constraint-runtime/src/services/index.js +12 -0
- package/dist/constraint-runtime/src/session_store.js +22 -0
- package/dist/constraint-runtime/src/setup.js +30 -0
- package/dist/constraint-runtime/src/skills/index.js +1 -0
- package/dist/constraint-runtime/src/skills/skill-registry.js +28 -0
- package/dist/constraint-runtime/src/state/index.js +12 -0
- package/dist/constraint-runtime/src/system_init.js +20 -0
- package/dist/constraint-runtime/src/thinking/engine.js +42 -0
- package/dist/constraint-runtime/src/thinking/index.js +1 -0
- package/dist/constraint-runtime/src/tool_pool.js +8 -0
- package/dist/constraint-runtime/src/tools/OpenCLI/execAdapter.js +7 -0
- package/dist/constraint-runtime/src/tools/OpenCLI/listAdapters.js +7 -0
- package/dist/constraint-runtime/src/tools/OpenCLI/runCommand.js +7 -0
- package/dist/constraint-runtime/src/tools/SafeSDK/confirmTransaction.js +6 -0
- package/dist/constraint-runtime/src/tools/SafeSDK/createTransaction.js +8 -0
- package/dist/constraint-runtime/src/tools/SafeSDK/executeTransaction.js +6 -0
- package/dist/constraint-runtime/src/tools/SafeSDK/getBalance.js +6 -0
- package/dist/constraint-runtime/src/tools/SafeSDK/getPendingTransactions.js +6 -0
- package/dist/constraint-runtime/src/tools/SafeSDK/proposeTransaction.js +6 -0
- package/dist/constraint-runtime/src/tools.js +80 -0
- package/dist/constraint-runtime/src/transcript.js +19 -0
- package/dist/constraint-runtime/src/types/index.js +12 -0
- package/dist/constraint-runtime/src/upstream_proxy/index.js +12 -0
- package/dist/constraint-runtime/src/utils/index.js +12 -0
- package/dist/constraint-runtime/src/vim/index.js +12 -0
- package/dist/constraint-runtime/src/voice/index.js +12 -0
- package/dist/constraint-runtime/tests/agent.test.js +16 -0
- package/dist/constraint-runtime/tests/constraint.test.js +41 -0
- package/dist/constraint-runtime/tests/skill.test.js +19 -0
- package/dist/constraint-runtime/tests/thinking.test.js +22 -0
- package/dist/context-compaction/auto-compact.js +7 -7
- package/dist/electron-preload.js +1 -18
- package/dist/electron-preload.js.map +1 -1
- package/dist/electron.js +168 -3
- package/dist/electron.js.map +1 -1
- package/dist/index.js +116 -136
- package/dist/llm/config-store.js +8 -24
- package/dist/llm/llm-judgment-client.js +102 -102
- package/dist/llm/pi-ai.js +85 -126
- package/dist/llm/system-prompt/layers/channel/local.md +14 -14
- package/dist/llm/system-prompt/layers/channel/p2p-agent.md +18 -18
- package/dist/llm/system-prompt/layers/channel/p2p-visitor.md +19 -19
- package/dist/llm/system-prompt/layers/core/artifacts_storage.md +89 -89
- package/dist/llm/system-prompt/layers/core/evenhandedness.md +21 -21
- package/dist/llm/system-prompt/layers/core/hibs_reminders.md +15 -15
- package/dist/llm/system-prompt/layers/core/identity.md +37 -37
- package/dist/llm/system-prompt/layers/core/knowledge.md +17 -17
- package/dist/llm/system-prompt/layers/core/memory_system.md +12 -12
- package/dist/llm/system-prompt/layers/core/network_filesystem.md +28 -28
- package/dist/llm/system-prompt/layers/core/refusal.md +37 -37
- package/dist/llm/system-prompt/layers/core/tone.md +31 -31
- package/dist/llm/system-prompt/layers/core/tools.thin.md +13 -13
- package/dist/llm/system-prompt/layers/core/wellbeing.md +41 -41
- package/dist/llm/system-prompt/layers/role/architect.md +20 -20
- package/dist/llm/system-prompt/layers/role/expert.md +19 -19
- package/dist/llm/system-prompt/layers/role/implementer.md +15 -15
- package/dist/llm/system-prompt/layers/role/security.md +15 -15
- package/dist/llm/system-prompt/layers/tool/artifacts.md +72 -72
- package/dist/llm/system-prompt/layers/tool/bash.md +25 -25
- package/dist/llm/system-prompt/layers/tool/hibs_api.md +171 -171
- package/dist/llm/system-prompt/layers/tool/image_search.md +70 -70
- package/dist/llm/system-prompt/layers/tool/manifest.md +89 -89
- package/dist/llm/system-prompt/layers/tool/mcp_apps.md +53 -53
- package/dist/llm/system-prompt/layers/tool/web_search.md +83 -83
- package/dist/llm/tool-manifest/ask_user_input.js +1 -1
- package/dist/llm/tool-manifest/bash.js +3 -3
- package/dist/llm/tool-manifest/create_file.js +4 -4
- package/dist/llm/tool-manifest/fetch_sports_data.js +3 -3
- package/dist/llm/tool-manifest/image_search.js +2 -2
- package/dist/llm/tool-manifest/mcp.js +2 -2
- package/dist/llm/tool-manifest/message_compose.js +3 -3
- package/dist/llm/tool-manifest/places.js +2 -2
- package/dist/llm/tool-manifest/present_files.js +1 -1
- package/dist/llm/tool-manifest/recipe.js +2 -2
- package/dist/llm/tool-manifest/str_replace.js +5 -5
- package/dist/llm/tool-manifest/view.js +3 -3
- package/dist/llm/tool-manifest/weather.js +4 -4
- package/dist/llm/tool-manifest/web.js +4 -4
- package/dist/pi-ecosystem-colony/index.js +365 -0
- package/dist/pi-ecosystem-judgment/causal-judge.js +51 -51
- package/dist/pi-ecosystem-judgment/distill-prompt.js +42 -42
- package/dist/pi-ecosystem-judgment/distillation.js +14 -14
- package/dist/pi-ecosystem-judgment/monitor-gate.js +28 -28
- package/dist/pi-ecosystem-judgment/value-injection.js +102 -102
- package/dist/security/context-router-tool.js +15 -15
- package/dist/security/tool-gate.js +0 -11
- package/dist/social/ant-colony/AdaptiveHeartbeat.js +101 -0
- package/dist/social/ant-colony/PheromoneEngine.js +227 -0
- package/dist/social/ant-colony/index.js +6 -0
- package/dist/social/ant-colony/types.js +24 -0
- package/dist/test/ai-judgment-test.js +80 -0
- package/dist/test/bollharness-integration.test.js +318 -0
- package/dist/test/channel-agent-multi-dialogue.js +205 -0
- package/dist/test/channel-heartbeat-agent-test.js +201 -0
- package/dist/test/constraint-layer.test.js +164 -0
- package/dist/test/diap-identity-test.js +172 -0
- package/dist/test/diap-quick-test.js +62 -0
- package/dist/test/global-shared-context.test.js +315 -0
- package/dist/test/harness-judgment-injection.test.js +246 -0
- package/dist/test/harness-workflow-integrator-test.js +228 -0
- package/dist/test/human-value-store.test.js +243 -0
- package/dist/test/hybrid-integration-test.js +118 -0
- package/dist/test/hybrid-messenger-verify.js +55 -0
- package/dist/test/iroh-bistream-debug.js +38 -0
- package/dist/test/iroh-communication.test.js +66 -0
- package/dist/test/iroh-debug-test.js +57 -0
- package/dist/test/iroh-diap-test.js +71 -0
- package/dist/test/iroh-direct-connect.js +55 -0
- package/dist/test/iroh-e2e-fixed.js +89 -0
- package/dist/test/iroh-e2e-same-process.js +63 -0
- package/dist/test/iroh-e2e.js +66 -0
- package/dist/test/iroh-final-e2e.js +72 -0
- package/dist/test/iroh-relay-test.js +37 -0
- package/dist/test/iroh-simple-test.js +41 -0
- package/dist/test/iroh-transport-verify.js +54 -0
- package/dist/test/iroh-transport.test.js +37 -0
- package/dist/test/iroh-two-nodes.js +70 -0
- package/dist/test/iroh-verify.js +44 -0
- package/dist/test/judgment-decision.test.js +219 -0
- package/dist/test/llm-judgment-integration.test.js +220 -0
- package/dist/test/p2p-agent-complex-dialogue.js +385 -0
- package/dist/test/p2p-agent-dialogue.js +341 -0
- package/dist/test/p2p-agent-full-bidirectional.js +510 -0
- package/dist/test/p2p-agent-harness-flow.js +437 -0
- package/dist/test/p2p-agent-harness-single.js +143 -0
- package/dist/test/p2p-ai-dialogue-test.js +318 -0
- package/dist/test/p2p-cid-connect-test.js +195 -0
- package/dist/test/p2p-connect-receiver.js +69 -0
- package/dist/test/p2p-doc-transfer.js +110 -0
- package/dist/test/p2p-identity-page-test.js +77 -0
- package/dist/test/p2p-iroh-test.js +171 -0
- package/dist/test/p2p-minimal-test.js +241 -0
- package/dist/test/p2p-node-1.js +148 -0
- package/dist/test/p2p-node-2.js +148 -0
- package/dist/test/p2p-server.js +281 -0
- package/dist/test/p2p-two-nodes-test.js +438 -0
- package/dist/test/pi-sdk.test.js +44 -0
- package/dist/test/set-persona.js +40 -0
- package/dist/test/simple.test.js +9 -0
- package/dist/test/storage-integration.test.js +150 -0
- package/dist/test/subagent-manager.test.js +276 -0
- package/dist/test/test-gate-flow.test.js +81 -0
- package/dist/test/workflow-engine.test.js +87 -0
- package/dist/test/workflow-pivot-loop.test.js +246 -0
- package/dist/web/api-config.html +520 -520
- package/dist/web/client.js +2917 -3791
- package/dist/web/components/p2p/index.js +234 -276
- package/dist/web/components/wallet-viem.mjs +118 -118
- package/dist/web/index.html +374 -373
- package/dist/web/manifest.json +20 -20
- package/dist/web/server.js +23 -775
- package/dist/web/style.css +4737 -4737
- package/dist/web/ui/message-renderer.js +373 -451
- package/dist/web/ui/step-timeline.js +255 -351
- package/package.json +160 -160
- package/scripts/build-cli.js +215 -215
- package/scripts/build-web.ts +125 -125
- package/scripts/postinstall.js +152 -152
- package/bin/bolloon-daemon.sh +0 -207
- package/bin/ipfs +0 -0
- package/dist/agents/chat-segmenter.js +0 -298
- package/dist/agents/judgment-protocol.js +0 -479
- package/dist/agents/parse-tool-call.js +0 -304
- package/dist/agents/peer-manifest-loader.js +0 -210
- package/dist/agents/react-loop.js +0 -120
- package/dist/agents/session-store.js +0 -171
- package/dist/agents/tool-registry.js +0 -136
- package/dist/bootstrap/chat-archiver.js +0 -276
- package/dist/bootstrap/memory-compressor.js +0 -170
- package/dist/bootstrap/persona-loader.js +0 -94
- package/dist/electron/config.js +0 -16
- package/dist/electron/config.js.map +0 -1
- package/dist/electron/dialogs.js +0 -71
- package/dist/electron/dialogs.js.map +0 -1
- package/dist/electron/first-run.js +0 -129
- package/dist/electron/first-run.js.map +0 -1
- package/dist/electron/ipc.js +0 -16
- package/dist/electron/ipc.js.map +0 -1
- package/dist/electron/logger.js +0 -77
- package/dist/electron/logger.js.map +0 -1
- package/dist/electron/main.js +0 -60
- package/dist/electron/main.js.map +0 -1
- package/dist/electron/menu.js +0 -140
- package/dist/electron/menu.js.map +0 -1
- package/dist/electron/paths.js +0 -33
- package/dist/electron/paths.js.map +0 -1
- package/dist/electron/server.js +0 -74
- package/dist/electron/server.js.map +0 -1
- package/dist/electron/tray.js +0 -73
- package/dist/electron/tray.js.map +0 -1
- package/dist/electron/window.js +0 -69
- package/dist/electron/window.js.map +0 -1
- package/dist/network/local-inbox-bus.js +0 -73
- package/dist/network/p2p-outbox.js +0 -161
- package/dist/network/peer-fs.js +0 -420
- package/dist/network/peer-resource-bridge.js +0 -216
- package/dist/web/components/p2p/P2PModal.js +0 -188
- package/dist/web/components/p2p/p2p-modal.js +0 -664
- package/dist/web/components/p2p/p2p-tools.js +0 -248
- package/dist/web/input-validator.js +0 -103
- package/dist/web/util/safe-name.js +0 -32
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Memory Compressor — session 消息 → LLM 摘要 → ~/.bolloon/memory/<agentId>/sessions/
|
|
3
|
-
*
|
|
4
|
-
* 触发: 每次 /message 处理后, saveSession 之后 (server.ts:2073 之后)
|
|
5
|
-
* 行为:
|
|
6
|
-
* - 读 session messages
|
|
7
|
-
* - 只压缩 cursor 之后的增量 (≥ 4 条新 messages 才压缩, 防频繁)
|
|
8
|
-
* - 调 LLM 生成中文摘要 (失败 fallback 到纯模板)
|
|
9
|
-
* - append 模式写入 <safe-channelId>__<safe-sessionId>.summary.md
|
|
10
|
-
* - 维护 cursor 文件 <safe-channelId>__<safe-sessionId>.cursor
|
|
11
|
-
*
|
|
12
|
-
* 失败静默: 调用方 try/catch 后 console.warn, 不阻塞主对话.
|
|
13
|
-
*/
|
|
14
|
-
import * as fs from 'fs/promises';
|
|
15
|
-
import * as os from 'os';
|
|
16
|
-
import * as path from 'path';
|
|
17
|
-
export function sanitizeAgentId(id) {
|
|
18
|
-
return id.replace(/[^a-zA-Z0-9_-]/g, '_').slice(0, 64);
|
|
19
|
-
}
|
|
20
|
-
export function sanitizeKey(id) {
|
|
21
|
-
return id.replace(/[^a-zA-Z0-9_.-]/g, '_').slice(0, 128);
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* ~/.bolloon/memory/<sanitizedAgentId>/
|
|
25
|
-
*/
|
|
26
|
-
export function getMemoryDir(agentId, home) {
|
|
27
|
-
return path.join(home || os.homedir(), '.bolloon', 'memory', sanitizeAgentId(agentId));
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* ~/.bolloon/memory/<agentId>/sessions/<safe-channelId>__<safe-sessionId>.summary.md
|
|
31
|
-
*/
|
|
32
|
-
export function getSessionSummaryPath(agentId, channelId, sessionId, home) {
|
|
33
|
-
const key = `${sanitizeKey(channelId)}__${sanitizeKey(sessionId)}`;
|
|
34
|
-
return path.join(getMemoryDir(agentId, home), 'sessions', `${key}.summary.md`);
|
|
35
|
-
}
|
|
36
|
-
export function getSessionCursorPath(agentId, channelId, sessionId, home) {
|
|
37
|
-
const key = `${sanitizeKey(channelId)}__${sanitizeKey(sessionId)}`;
|
|
38
|
-
return path.join(getMemoryDir(agentId, home), 'sessions', `${key}.cursor`);
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Session 缓存文件路径 (跟 server.ts:1806 sessionKey 规则一致)
|
|
42
|
-
*/
|
|
43
|
-
function getSessionCacheFile(channelId, sessionId, home) {
|
|
44
|
-
const root = path.join(home || os.homedir(), '.bolloon', 'sessions', 'cache');
|
|
45
|
-
const safeChannel = sanitizeKey(channelId);
|
|
46
|
-
const safeSession = sanitizeKey(sessionId).replace(/:/g, '__');
|
|
47
|
-
return path.join(root, `${safeChannel}__${safeSession}.json`);
|
|
48
|
-
}
|
|
49
|
-
async function readCursor(cursorPath) {
|
|
50
|
-
try {
|
|
51
|
-
const raw = await fs.readFile(cursorPath, 'utf-8');
|
|
52
|
-
const n = parseInt(raw.trim(), 10);
|
|
53
|
-
return Number.isFinite(n) && n >= 0 ? n : 0;
|
|
54
|
-
}
|
|
55
|
-
catch {
|
|
56
|
-
return 0;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
async function writeCursor(cursorPath, value) {
|
|
60
|
-
await fs.mkdir(path.dirname(cursorPath), { recursive: true });
|
|
61
|
-
await fs.writeFile(cursorPath, String(value), 'utf-8');
|
|
62
|
-
}
|
|
63
|
-
async function readSessionMessages(sessionCacheFile) {
|
|
64
|
-
try {
|
|
65
|
-
const raw = await fs.readFile(sessionCacheFile, 'utf-8');
|
|
66
|
-
const parsed = JSON.parse(raw);
|
|
67
|
-
if (Array.isArray(parsed))
|
|
68
|
-
return parsed;
|
|
69
|
-
if (Array.isArray(parsed.messages))
|
|
70
|
-
return parsed.messages;
|
|
71
|
-
return [];
|
|
72
|
-
}
|
|
73
|
-
catch {
|
|
74
|
-
return [];
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* 纯模板摘要 (LLM 失败 fallback, 不依赖外部调用)
|
|
79
|
-
*/
|
|
80
|
-
function templateSummary(opts) {
|
|
81
|
-
const userMsgs = opts.newMessages.filter(m => m.type === 'user');
|
|
82
|
-
const aiMsgs = opts.newMessages.filter(m => m.type === 'ai');
|
|
83
|
-
const userSnippet = userMsgs.slice(0, 3).map(m => ` - ${m.content.slice(0, 80)}`).join('\n');
|
|
84
|
-
const aiSnippet = aiMsgs.slice(0, 3).map(m => ` - ${m.content.slice(0, 80)}`).join('\n');
|
|
85
|
-
return `# Session 摘要 — ${opts.channelId} / ${opts.sessionId}
|
|
86
|
-
|
|
87
|
-
时间: ${opts.timestamp}
|
|
88
|
-
新增消息数: ${opts.newMessages.length} (user=${userMsgs.length}, ai=${aiMsgs.length})
|
|
89
|
-
|
|
90
|
-
## 用户关键提问
|
|
91
|
-
${userSnippet || ' (无)'}
|
|
92
|
-
|
|
93
|
-
## AI 关键回答
|
|
94
|
-
${aiSnippet || ' (无)'}
|
|
95
|
-
|
|
96
|
-
## 备注
|
|
97
|
-
- 此摘要由模板生成 (LLM 调用失败 fallback)
|
|
98
|
-
`;
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* 尝试调 LLM 生成更精炼的中文摘要. 失败 → 抛错, 由 caller fallback.
|
|
102
|
-
*
|
|
103
|
-
* 用动态 import + 失败静默 — 不引入 pi-ai 强依赖 (避免循环).
|
|
104
|
-
*/
|
|
105
|
-
async function tryLlmSummary(systemPrompt, userPrompt) {
|
|
106
|
-
try {
|
|
107
|
-
const piAi = await import('../llm/pi-ai.js');
|
|
108
|
-
const generateText = piAi.generateText;
|
|
109
|
-
if (typeof generateText !== 'function')
|
|
110
|
-
throw new Error('generateText not exported');
|
|
111
|
-
const result = await generateText({
|
|
112
|
-
messages: [
|
|
113
|
-
{ role: 'system', content: systemPrompt },
|
|
114
|
-
{ role: 'user', content: userPrompt },
|
|
115
|
-
],
|
|
116
|
-
temperature: 0.2,
|
|
117
|
-
maxTokens: 800,
|
|
118
|
-
});
|
|
119
|
-
const text = result?.reply || result?.text || '';
|
|
120
|
-
if (typeof text !== 'string' || text.length < 20)
|
|
121
|
-
throw new Error('LLM returned too-short text');
|
|
122
|
-
return text;
|
|
123
|
-
}
|
|
124
|
-
catch (e) {
|
|
125
|
-
throw new Error(`LLM call failed: ${e?.message || String(e)}`);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
export async function compressSessionToMemory(opts) {
|
|
129
|
-
const agentId = sanitizeAgentId(opts.agentId);
|
|
130
|
-
const home = opts.home || os.homedir();
|
|
131
|
-
const summaryPath = getSessionSummaryPath(agentId, opts.channelId, opts.sessionId, home);
|
|
132
|
-
const cursorPath = getSessionCursorPath(agentId, opts.channelId, opts.sessionId, home);
|
|
133
|
-
const sessionCacheFile = getSessionCacheFile(opts.channelId, opts.sessionId, home);
|
|
134
|
-
const allMessages = await readSessionMessages(sessionCacheFile);
|
|
135
|
-
const cursor = await readCursor(cursorPath);
|
|
136
|
-
const newMessages = allMessages.slice(cursor);
|
|
137
|
-
const minNew = opts.minNewMessages ?? 4;
|
|
138
|
-
if (allMessages.length === 0) {
|
|
139
|
-
return { summaryPath, cursorPath, messagesCount: 0, bytesWritten: 0, skipped: 'no-new-messages' };
|
|
140
|
-
}
|
|
141
|
-
if (newMessages.length < minNew) {
|
|
142
|
-
return { summaryPath, cursorPath, messagesCount: newMessages.length, bytesWritten: 0, skipped: 'too-few-messages' };
|
|
143
|
-
}
|
|
144
|
-
const timestamp = new Date().toISOString();
|
|
145
|
-
let summaryBody;
|
|
146
|
-
try {
|
|
147
|
-
const sysPrompt = '你是 bolloon 记忆压缩助手. 输入是一段 session 消息历史 (用户问题 + AI 回答), 输出 200-400 字中文摘要, 包含 3-5 条关键发现和未完成事项. 不要寒暄, 不要复述已知. 格式: ## 关键发现 / ## 待办.';
|
|
148
|
-
const recentSnippet = newMessages.slice(-10).map(m => `[${m.type}] ${m.content}`).join('\n---\n').slice(0, 6000);
|
|
149
|
-
const userPrompt = `Channel: ${opts.channelId}\nSession: ${opts.sessionId}\n时间: ${timestamp}\n新增消息数: ${newMessages.length}\n\n最近消息:\n${recentSnippet}`;
|
|
150
|
-
summaryBody = await tryLlmSummary(sysPrompt, userPrompt);
|
|
151
|
-
}
|
|
152
|
-
catch (e) {
|
|
153
|
-
summaryBody = templateSummary({
|
|
154
|
-
channelId: opts.channelId,
|
|
155
|
-
sessionId: opts.sessionId,
|
|
156
|
-
newMessages,
|
|
157
|
-
timestamp,
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
const block = `\n\n---\n\n## 增量摘要 @ ${timestamp} (${newMessages.length} messages)\n\n${summaryBody.trim()}\n`;
|
|
161
|
-
await fs.mkdir(path.dirname(summaryPath), { recursive: true });
|
|
162
|
-
await fs.appendFile(summaryPath, block, 'utf-8');
|
|
163
|
-
await writeCursor(cursorPath, allMessages.length);
|
|
164
|
-
return {
|
|
165
|
-
summaryPath,
|
|
166
|
-
cursorPath,
|
|
167
|
-
messagesCount: newMessages.length,
|
|
168
|
-
bytesWritten: Buffer.byteLength(block, 'utf-8'),
|
|
169
|
-
};
|
|
170
|
-
}
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Persona Documents Loader — ~/.bolloon/persona/<agentId>/*.md
|
|
3
|
-
*
|
|
4
|
-
* 失败静默: 文件不存在 → 字段 = '', 不抛错
|
|
5
|
-
* 安全: agentId sanitize (防路径穿越)
|
|
6
|
-
* 6 段输出顺序: identity → soul → project → user → agent → wiki
|
|
7
|
-
*/
|
|
8
|
-
import * as fs from 'fs/promises';
|
|
9
|
-
import * as os from 'os';
|
|
10
|
-
import * as path from 'path';
|
|
11
|
-
const FILE_KEYS = ['soul', 'identity', 'project', 'user', 'agent', 'wiki'];
|
|
12
|
-
/**
|
|
13
|
-
* 安全转 agentId: 只保留 [a-zA-Z0-9_-], 限长 64
|
|
14
|
-
* 防止路径穿越 ('/', '..', '\\\\' 都变 '_')
|
|
15
|
-
*/
|
|
16
|
-
export function sanitizeAgentId(id) {
|
|
17
|
-
return id.replace(/[^a-zA-Z0-9_-]/g, '_').slice(0, 64);
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* 读 ~/.bolloon/persona/<sanitizedAgentId>/{6 files}
|
|
21
|
-
* 文件不存在 → 该字段 = ''
|
|
22
|
-
*/
|
|
23
|
-
export async function loadPersonaDocs(agentId, home) {
|
|
24
|
-
const safeId = sanitizeAgentId(agentId);
|
|
25
|
-
const root = home || os.homedir();
|
|
26
|
-
const baseDir = path.join(root, '.bolloon', 'persona', safeId);
|
|
27
|
-
const docs = {
|
|
28
|
-
agentId: safeId,
|
|
29
|
-
soul: '',
|
|
30
|
-
identity: '',
|
|
31
|
-
project: '',
|
|
32
|
-
user: '',
|
|
33
|
-
agent: '',
|
|
34
|
-
wiki: '',
|
|
35
|
-
};
|
|
36
|
-
await Promise.all(FILE_KEYS.map(async (key) => {
|
|
37
|
-
const file = path.join(baseDir, `${key}.md`);
|
|
38
|
-
try {
|
|
39
|
-
const content = await fs.readFile(file, 'utf-8');
|
|
40
|
-
docs[key] = content;
|
|
41
|
-
}
|
|
42
|
-
catch {
|
|
43
|
-
docs[key] = '';
|
|
44
|
-
}
|
|
45
|
-
}));
|
|
46
|
-
return docs;
|
|
47
|
-
}
|
|
48
|
-
const DEFAULT_MAX_CHARS = 4000;
|
|
49
|
-
const SECTION_LABELS = {
|
|
50
|
-
identity: 'Identity',
|
|
51
|
-
soul: 'Soul',
|
|
52
|
-
project: 'Project',
|
|
53
|
-
user: 'User',
|
|
54
|
-
agent: 'Agent',
|
|
55
|
-
wiki: 'Wiki',
|
|
56
|
-
};
|
|
57
|
-
const OUTPUT_ORDER = ['identity', 'soul', 'project', 'user', 'agent', 'wiki'];
|
|
58
|
-
/**
|
|
59
|
-
* 把 PersonaDocs 格式化成 markdown 段, 拼到 system prompt 头部.
|
|
60
|
-
*
|
|
61
|
-
* 超 maxChars 时按比例截断: 每个字段都保留头部,
|
|
62
|
-
* 保证 6 段标识都出现, 不砍段.
|
|
63
|
-
*/
|
|
64
|
-
export function formatPersonaForSystemPrompt(docs, maxChars) {
|
|
65
|
-
const cap = maxChars ?? DEFAULT_MAX_CHARS;
|
|
66
|
-
// 段: 标识 + 字段值 (空字段跳过)
|
|
67
|
-
const sections = [];
|
|
68
|
-
for (const key of OUTPUT_ORDER) {
|
|
69
|
-
const v = docs[key];
|
|
70
|
-
if (v && v.length > 0) {
|
|
71
|
-
sections.push({ key, text: `## ${SECTION_LABELS[key]}\n${v}` });
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
if (sections.length === 0)
|
|
75
|
-
return '';
|
|
76
|
-
// 预算每段 (去掉 ## 标识和换行的固定开销)
|
|
77
|
-
const header = `# Persona (agentId=${docs.agentId})\n\n`;
|
|
78
|
-
const fixedOverhead = header.length + (sections.length - 1) * 2;
|
|
79
|
-
const perSectionBudget = Math.max(50, Math.floor((cap - fixedOverhead) / sections.length));
|
|
80
|
-
const parts = [header.trim()];
|
|
81
|
-
for (const sec of sections) {
|
|
82
|
-
let body = sec.text;
|
|
83
|
-
if (body.length > perSectionBudget) {
|
|
84
|
-
body = body.substring(0, perSectionBudget) + '\n... (截断)';
|
|
85
|
-
}
|
|
86
|
-
parts.push(body);
|
|
87
|
-
}
|
|
88
|
-
let result = parts.join('\n\n');
|
|
89
|
-
if (result.length > cap) {
|
|
90
|
-
const truncateMarker = '\n... (截断)';
|
|
91
|
-
result = result.substring(0, Math.max(0, cap - truncateMarker.length)) + truncateMarker;
|
|
92
|
-
}
|
|
93
|
-
return result;
|
|
94
|
-
}
|
package/dist/electron/config.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 常量配置 (env 解析在这里集中, 不散在 main 流程)
|
|
3
|
-
*/
|
|
4
|
-
import { app } from 'electron';
|
|
5
|
-
export const DEFAULT_PORT = 54188;
|
|
6
|
-
/** Hard-pin to loopback; LAN exposure must be explicit. */
|
|
7
|
-
export const DEFAULT_HOST = '127.0.0.1';
|
|
8
|
-
export const WEB_SERVER_STARTUP_TIMEOUT_MS = 15_000;
|
|
9
|
-
export const MAIN_WINDOW_DEFAULT = { width: 1200, height: 800 };
|
|
10
|
-
export const MAIN_WINDOW_MIN = { width: 800, height: 600 };
|
|
11
|
-
export function preferredPort() {
|
|
12
|
-
const raw = process.env.ELECTRON_PORT || process.env.PORT;
|
|
13
|
-
const n = parseInt(raw || '', 10);
|
|
14
|
-
return Number.isFinite(n) && n > 0 && n < 65536 ? n : DEFAULT_PORT;
|
|
15
|
-
}
|
|
16
|
-
export const isDev = process.env.NODE_ENV === 'development' || !app.isPackaged;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/electron/config.ts"],"names":[],"mappings":";;;AAcA,sCAIC;AAlBD;;GAEG;AACH,uCAA+B;AAElB,QAAA,YAAY,GAAG,KAAK,CAAC;AAClC,2DAA2D;AAC9C,QAAA,YAAY,GAAG,WAAW,CAAC;AAE3B,QAAA,6BAA6B,GAAG,MAAM,CAAC;AAEvC,QAAA,mBAAmB,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;AACnD,QAAA,eAAe,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;AAE3D,SAAgB,aAAa;IAC3B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;IAC1D,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IAClC,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,oBAAY,CAAC;AACrE,CAAC;AAEY,QAAA,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,IAAI,CAAC,cAAG,CAAC,UAAU,CAAC"}
|
package/dist/electron/dialogs.js
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 文件 dialog 桥 (open / save / dir) + 安全的 fs 桥 (read / write / exists)
|
|
3
|
-
*
|
|
4
|
-
* 5MB read 上限保护 — 渲染进程直接 fs.readFile 没法做限制, 走主进程就有界
|
|
5
|
-
* 所有 handler 解析 event.sender 拿到 window, 让 dialog 模态在该窗口上
|
|
6
|
-
*/
|
|
7
|
-
import { BrowserWindow, dialog, ipcMain } from 'electron';
|
|
8
|
-
import * as fs from 'fs';
|
|
9
|
-
import * as path from 'path';
|
|
10
|
-
import { log } from './logger';
|
|
11
|
-
const MAX_READ_BYTES = 5 * 1024 * 1024; // 5MB
|
|
12
|
-
function windowFor(event) {
|
|
13
|
-
return BrowserWindow.fromWebContents(event.sender);
|
|
14
|
-
}
|
|
15
|
-
function resolveSafe(target) {
|
|
16
|
-
// 不去硬限制路径 — user 给 renderer 暴露 fs 已经信任了, 这里只 normalize
|
|
17
|
-
return path.resolve(target);
|
|
18
|
-
}
|
|
19
|
-
export function registerDialogIpc() {
|
|
20
|
-
ipcMain.handle('dialog:open-file', async (event, opts = {}) => {
|
|
21
|
-
const win = windowFor(event);
|
|
22
|
-
const result = await dialog.showOpenDialog(win, {
|
|
23
|
-
title: opts.title,
|
|
24
|
-
defaultPath: opts.defaultPath,
|
|
25
|
-
filters: opts.filters,
|
|
26
|
-
properties: opts.properties ?? ['openFile'],
|
|
27
|
-
});
|
|
28
|
-
return { canceled: result.canceled, filePaths: result.filePaths };
|
|
29
|
-
});
|
|
30
|
-
ipcMain.handle('dialog:save-file', async (event, opts = {}) => {
|
|
31
|
-
const win = windowFor(event);
|
|
32
|
-
const result = await dialog.showSaveDialog(win, {
|
|
33
|
-
title: opts.title,
|
|
34
|
-
defaultPath: opts.defaultPath,
|
|
35
|
-
filters: opts.filters,
|
|
36
|
-
});
|
|
37
|
-
return { canceled: result.canceled, filePath: result.filePath };
|
|
38
|
-
});
|
|
39
|
-
ipcMain.handle('dialog:open-directory', async (event, opts = {}) => {
|
|
40
|
-
const win = windowFor(event);
|
|
41
|
-
const result = await dialog.showOpenDialog(win, {
|
|
42
|
-
title: opts.title,
|
|
43
|
-
defaultPath: opts.defaultPath,
|
|
44
|
-
properties: ['openDirectory', 'createDirectory'],
|
|
45
|
-
});
|
|
46
|
-
return { canceled: result.canceled, filePaths: result.filePaths };
|
|
47
|
-
});
|
|
48
|
-
ipcMain.handle('fs:read-text-file', async (_event, opts) => {
|
|
49
|
-
const target = resolveSafe(opts.path);
|
|
50
|
-
const stat = fs.statSync(target);
|
|
51
|
-
if (stat.size > MAX_READ_BYTES) {
|
|
52
|
-
throw new Error(`文件过大: ${stat.size} > ${MAX_READ_BYTES} bytes`);
|
|
53
|
-
}
|
|
54
|
-
return fs.readFileSync(target, { encoding: opts.encoding ?? 'utf8' });
|
|
55
|
-
});
|
|
56
|
-
ipcMain.handle('fs:write-text-file', async (_event, opts) => {
|
|
57
|
-
const target = resolveSafe(opts.path);
|
|
58
|
-
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
59
|
-
fs.writeFileSync(target, opts.content, { encoding: opts.encoding ?? 'utf8' });
|
|
60
|
-
});
|
|
61
|
-
ipcMain.handle('fs:path-exists', async (_event, opts) => {
|
|
62
|
-
try {
|
|
63
|
-
fs.accessSync(resolveSafe(opts.path));
|
|
64
|
-
return true;
|
|
65
|
-
}
|
|
66
|
-
catch {
|
|
67
|
-
return false;
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
log('dialog + fs IPC handlers registered');
|
|
71
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dialogs.js","sourceRoot":"","sources":["../../src/electron/dialogs.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 首启检测 + 引导浮层
|
|
3
|
-
*
|
|
4
|
-
* 标记文件写在 userData (不是 ~/.bolloon/), 卸载 app 自然清掉
|
|
5
|
-
* 引导窗是父主窗的 modal, frame=false, 透明背景; 关闭时标记写入
|
|
6
|
-
*/
|
|
7
|
-
import { BrowserWindow, app, ipcMain } from 'electron';
|
|
8
|
-
import * as fs from 'fs';
|
|
9
|
-
import * as path from 'path';
|
|
10
|
-
import { firstRunFlagPath, dataDir, logsDir } from './paths';
|
|
11
|
-
import { log } from './logger';
|
|
12
|
-
const OVERLAY_HTML = `
|
|
13
|
-
<!DOCTYPE html>
|
|
14
|
-
<html>
|
|
15
|
-
<head>
|
|
16
|
-
<meta charset="utf-8" />
|
|
17
|
-
<style>
|
|
18
|
-
:root { color-scheme: light dark; }
|
|
19
|
-
body {
|
|
20
|
-
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
21
|
-
margin: 0; padding: 32px 28px;
|
|
22
|
-
background: rgba(245,245,247,0.97);
|
|
23
|
-
color: #1d1d1f;
|
|
24
|
-
height: 100vh; box-sizing: border-box;
|
|
25
|
-
}
|
|
26
|
-
@media (prefers-color-scheme: dark) {
|
|
27
|
-
body { background: rgba(28,28,30,0.97); color: #f5f5f7; }
|
|
28
|
-
}
|
|
29
|
-
h1 { font-size: 18px; margin: 0 0 14px; font-weight: 600; }
|
|
30
|
-
p { font-size: 13px; line-height: 1.55; margin: 8px 0; }
|
|
31
|
-
code {
|
|
32
|
-
font-family: ui-monospace, "SF Mono", Menlo, monospace;
|
|
33
|
-
font-size: 12px; padding: 1px 5px;
|
|
34
|
-
background: rgba(0,0,0,0.06); border-radius: 3px;
|
|
35
|
-
}
|
|
36
|
-
@media (prefers-color-scheme: dark) {
|
|
37
|
-
code { background: rgba(255,255,255,0.08); }
|
|
38
|
-
}
|
|
39
|
-
.btn {
|
|
40
|
-
display: inline-block; margin-top: 18px; padding: 8px 18px;
|
|
41
|
-
background: #007aff; color: #fff; border: none; border-radius: 6px;
|
|
42
|
-
font-size: 13px; font-weight: 500; cursor: pointer;
|
|
43
|
-
}
|
|
44
|
-
.btn:hover { background: #0066d6; }
|
|
45
|
-
ul { padding-left: 20px; }
|
|
46
|
-
li { font-size: 13px; line-height: 1.7; }
|
|
47
|
-
</style>
|
|
48
|
-
</head>
|
|
49
|
-
<body>
|
|
50
|
-
<h1>欢迎使用 Bolloon Agent</h1>
|
|
51
|
-
<p>你的数据存放在本地, 不上传:</p>
|
|
52
|
-
<ul>
|
|
53
|
-
<li>配置 / 频道 / P2P 密钥: <code id="data"></code></li>
|
|
54
|
-
<li>运行日志: <code id="logs"></code></li>
|
|
55
|
-
</ul>
|
|
56
|
-
<p>所有数据在卸载后仍保留 — 想清理就手动删除 ~/.bolloon/。</p>
|
|
57
|
-
<button class="btn" id="ok">知道了</button>
|
|
58
|
-
<script>
|
|
59
|
-
const ok = document.getElementById('ok');
|
|
60
|
-
ok.addEventListener('click', () => window.electronAPI.markFirstRunSeen());
|
|
61
|
-
document.getElementById('data').textContent = window.electronAPI.getDataPathSync?.() || '';
|
|
62
|
-
document.getElementById('logs').textContent = window.electronAPI.getLogsPathSync?.() || '';
|
|
63
|
-
</script>
|
|
64
|
-
</body>
|
|
65
|
-
</html>
|
|
66
|
-
`;
|
|
67
|
-
export function hasSeenFirstRun() {
|
|
68
|
-
try {
|
|
69
|
-
return fs.existsSync(firstRunFlagPath());
|
|
70
|
-
}
|
|
71
|
-
catch {
|
|
72
|
-
return false;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
export function markFirstRunSeen() {
|
|
76
|
-
try {
|
|
77
|
-
fs.mkdirSync(path.dirname(firstRunFlagPath()), { recursive: true });
|
|
78
|
-
fs.writeFileSync(firstRunFlagPath(), new Date().toISOString());
|
|
79
|
-
}
|
|
80
|
-
catch (err) {
|
|
81
|
-
log(`写入首启标记失败: ${err.message}`, 'warn');
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
export function showFirstRunOverlay(parent) {
|
|
85
|
-
return new Promise((resolve) => {
|
|
86
|
-
const overlay = new BrowserWindow({
|
|
87
|
-
parent,
|
|
88
|
-
modal: true,
|
|
89
|
-
frame: false,
|
|
90
|
-
transparent: true,
|
|
91
|
-
width: 520,
|
|
92
|
-
height: 360,
|
|
93
|
-
resizable: false,
|
|
94
|
-
movable: false,
|
|
95
|
-
minimizable: false,
|
|
96
|
-
maximizable: false,
|
|
97
|
-
title: 'Welcome',
|
|
98
|
-
});
|
|
99
|
-
const dataUrl = 'data:text/html;charset=utf-8,' + encodeURIComponent(OVERLAY_HTML);
|
|
100
|
-
overlay.loadURL(dataUrl);
|
|
101
|
-
// 一次性的 IPC handler, 关闭后清掉避免累积
|
|
102
|
-
const handler = () => {
|
|
103
|
-
markFirstRunSeen();
|
|
104
|
-
overlay.close();
|
|
105
|
-
};
|
|
106
|
-
ipcMain.once('first-run:ack', handler);
|
|
107
|
-
overlay.on('closed', () => {
|
|
108
|
-
ipcMain.removeListener('first-run:ack', handler);
|
|
109
|
-
resolve();
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
/** 注册 IPC handlers (给 preload 桥用) */
|
|
114
|
-
export function registerFirstRunIpc() {
|
|
115
|
-
ipcMain.handle('first-run:seen', () => hasSeenFirstRun());
|
|
116
|
-
ipcMain.handle('first-run:mark-seen', () => { markFirstRunSeen(); });
|
|
117
|
-
// 同步值 (不用 ipcRenderer.invoke 的 await) — 用 exposeInMainWorld 的 sync getter 更顺
|
|
118
|
-
ipcMain.handle('first-run:data-dir', () => dataDir());
|
|
119
|
-
ipcMain.handle('first-run:logs-dir', () => logsDir());
|
|
120
|
-
log('first-run IPC handlers registered');
|
|
121
|
-
}
|
|
122
|
-
/** 包装 — 决定要不要弹 overlay */
|
|
123
|
-
export async function maybeShowFirstRun(parent) {
|
|
124
|
-
if (hasSeenFirstRun())
|
|
125
|
-
return;
|
|
126
|
-
log('首启 — 弹出引导');
|
|
127
|
-
await showFirstRunOverlay(parent);
|
|
128
|
-
app.addRecentDocument(firstRunFlagPath()); // 跟踪最近文档, 让 user 知道有这文件
|
|
129
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"first-run.js","sourceRoot":"","sources":["../../src/electron/first-run.ts"],"names":[],"mappings":"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"}
|
package/dist/electron/ipc.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* IPC handler 集中注册 — version / userData path / open-external (legacy 3 个)
|
|
3
|
-
* dialog/fs 的注册在 dialogs.ts; updater 的注册在 updater.ts
|
|
4
|
-
*/
|
|
5
|
-
import { app, ipcMain, shell } from 'electron';
|
|
6
|
-
import { userDataDir, dataDir } from './paths';
|
|
7
|
-
import { log } from './logger';
|
|
8
|
-
export function registerCoreIpc() {
|
|
9
|
-
ipcMain.handle('get-version', () => app.getVersion());
|
|
10
|
-
ipcMain.handle('get-user-data-path', () => userDataDir());
|
|
11
|
-
ipcMain.handle('get-data-path', () => dataDir()); // 跟 userData 分开, 渲染层要用
|
|
12
|
-
ipcMain.handle('open-external', async (_event, url) => {
|
|
13
|
-
await shell.openExternal(url);
|
|
14
|
-
});
|
|
15
|
-
log('core IPC handlers registered');
|
|
16
|
-
}
|
package/dist/electron/ipc.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ipc.js","sourceRoot":"","sources":["../../src/electron/ipc.ts"],"names":[],"mappings":";;AAQA,0CAWC;AAnBD;;;GAGG;AACH,uCAA+C;AAC/C,mCAA+C;AAC/C,qCAA+B;AAE/B,SAAgB,eAAe;IAC7B,kBAAO,CAAC,MAAM,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,cAAG,CAAC,UAAU,EAAE,CAAC,CAAC;IAEtD,kBAAO,CAAC,MAAM,CAAC,oBAAoB,EAAE,GAAG,EAAE,CAAC,IAAA,mBAAW,GAAE,CAAC,CAAC;IAC1D,kBAAO,CAAC,MAAM,CAAC,eAAe,EAAE,GAAG,EAAE,CAAC,IAAA,eAAO,GAAE,CAAC,CAAC,CAAC,uBAAuB;IAEzE,kBAAO,CAAC,MAAM,CAAC,eAAe,EAAE,KAAK,EAAE,MAAM,EAAE,GAAW,EAAE,EAAE;QAC5D,MAAM,gBAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,IAAA,YAAG,EAAC,8BAA8B,CAAC,CAAC;AACtC,CAAC"}
|
package/dist/electron/logger.js
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 简单 logger: 写日志到 <userData>/logs/bolloon.log, size-based 轮转
|
|
3
|
-
* (5MB 上限, 保留 .1 .2 .3 共 3 个备份 → ~20MB 上限)
|
|
4
|
-
*
|
|
5
|
-
* 同步写是因为 Electron 主进程日志量小, 同步 append 简单可靠, 不丢日志.
|
|
6
|
-
* 量大的会话级 jsonl 走自己路径 (lifecycle-hooks 等), 跟本 logger 无关.
|
|
7
|
-
*/
|
|
8
|
-
import * as fs from 'fs';
|
|
9
|
-
import { mainLogPath, logsDir } from './paths';
|
|
10
|
-
const MAX_BYTES = 5 * 1024 * 1024;
|
|
11
|
-
const MAX_BACKUPS = 3; // 保留 bolloon.log.1 .2 .3
|
|
12
|
-
let currentSize = 0;
|
|
13
|
-
let initialized = false;
|
|
14
|
-
function ensureLogFile() {
|
|
15
|
-
if (initialized)
|
|
16
|
-
return;
|
|
17
|
-
initialized = true;
|
|
18
|
-
try {
|
|
19
|
-
fs.mkdirSync(logsDir(), { recursive: true });
|
|
20
|
-
try {
|
|
21
|
-
currentSize = fs.statSync(mainLogPath()).size;
|
|
22
|
-
}
|
|
23
|
-
catch {
|
|
24
|
-
currentSize = 0;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
catch (err) {
|
|
28
|
-
// 失败也无所谓, log() 内部会 swallow
|
|
29
|
-
currentSize = 0;
|
|
30
|
-
console.error('[logger] ensureLogFile failed:', err);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
function rotate() {
|
|
34
|
-
const logPath = mainLogPath();
|
|
35
|
-
for (let i = MAX_BACKUPS; i >= 1; i--) {
|
|
36
|
-
const src = `${logPath}.${i}`;
|
|
37
|
-
const dst = `${logPath}.${i + 1}`;
|
|
38
|
-
if (i === MAX_BACKUPS) {
|
|
39
|
-
try {
|
|
40
|
-
fs.unlinkSync(src);
|
|
41
|
-
}
|
|
42
|
-
catch { /* missing ok */ }
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
try {
|
|
46
|
-
fs.renameSync(src, dst);
|
|
47
|
-
}
|
|
48
|
-
catch { /* missing ok */ }
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
try {
|
|
52
|
-
fs.renameSync(logPath, `${logPath}.1`);
|
|
53
|
-
}
|
|
54
|
-
catch { /* missing ok */ }
|
|
55
|
-
currentSize = 0;
|
|
56
|
-
}
|
|
57
|
-
export function log(message, level = 'info') {
|
|
58
|
-
ensureLogFile();
|
|
59
|
-
const ts = new Date().toISOString();
|
|
60
|
-
const line = `[${ts}] [${level}] ${message}\n`;
|
|
61
|
-
if (currentSize + line.length > MAX_BYTES)
|
|
62
|
-
rotate();
|
|
63
|
-
try {
|
|
64
|
-
fs.appendFileSync(mainLogPath(), line);
|
|
65
|
-
currentSize += line.length;
|
|
66
|
-
}
|
|
67
|
-
catch (err) {
|
|
68
|
-
// 写不进就 console, 不要再递归 log
|
|
69
|
-
console.error('[logger] appendFileSync failed:', err);
|
|
70
|
-
}
|
|
71
|
-
if (level === 'error')
|
|
72
|
-
console.error(line.trimEnd());
|
|
73
|
-
else if (level === 'warn')
|
|
74
|
-
console.warn(line.trimEnd());
|
|
75
|
-
else
|
|
76
|
-
console.log(line.trimEnd());
|
|
77
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/electron/logger.ts"],"names":[],"mappings":"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"}
|
package/dist/electron/main.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Electron 主进程 lifecycle 入口
|
|
3
|
-
* 单实例锁 → whenReady → createMainWindow → cleanup on quit
|
|
4
|
-
* 启动时: 装 menu / tray / IPC handlers / 首启引导
|
|
5
|
-
*/
|
|
6
|
-
import { app, BrowserWindow } from 'electron';
|
|
7
|
-
import { log } from './logger';
|
|
8
|
-
import { createMainWindow, focusMainWindow, getMainWindow } from './window';
|
|
9
|
-
import { killWebServer } from './server';
|
|
10
|
-
import { installAppMenu } from './menu';
|
|
11
|
-
import { createTray, destroyTray } from './tray';
|
|
12
|
-
import { registerCoreIpc } from './ipc';
|
|
13
|
-
import { registerDialogIpc } from './dialogs';
|
|
14
|
-
import { registerFirstRunIpc, maybeShowFirstRun } from './first-run';
|
|
15
|
-
log('Bolloon Electron 启动');
|
|
16
|
-
// 单实例锁
|
|
17
|
-
const gotTheLock = app.requestSingleInstanceLock();
|
|
18
|
-
if (!gotTheLock) {
|
|
19
|
-
log('已有实例在运行,退出');
|
|
20
|
-
app.quit();
|
|
21
|
-
}
|
|
22
|
-
app.on('second-instance', () => {
|
|
23
|
-
focusMainWindow();
|
|
24
|
-
});
|
|
25
|
-
app.whenReady().then(async () => {
|
|
26
|
-
log('Electron 准备好');
|
|
27
|
-
registerCoreIpc();
|
|
28
|
-
registerDialogIpc();
|
|
29
|
-
registerFirstRunIpc();
|
|
30
|
-
installAppMenu(getMainWindow);
|
|
31
|
-
createTray(getMainWindow);
|
|
32
|
-
await createMainWindow();
|
|
33
|
-
// 首启引导 (在主窗口就绪后弹, 不阻塞 UI)
|
|
34
|
-
const win = getMainWindow();
|
|
35
|
-
if (win) {
|
|
36
|
-
win.webContents.once('did-finish-load', () => {
|
|
37
|
-
void maybeShowFirstRun(win);
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
app.on('activate', async () => {
|
|
41
|
-
// macOS: dock 图标被点击且没有窗口时, 重开
|
|
42
|
-
if (BrowserWindow.getAllWindows().length === 0) {
|
|
43
|
-
await createMainWindow();
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
app.on('window-all-closed', () => {
|
|
48
|
-
log('所有窗口已关闭');
|
|
49
|
-
destroyTray();
|
|
50
|
-
killWebServer();
|
|
51
|
-
if (process.platform !== 'darwin') {
|
|
52
|
-
app.quit();
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
app.on('before-quit', () => {
|
|
56
|
-
log('应用即将退出');
|
|
57
|
-
destroyTray();
|
|
58
|
-
killWebServer();
|
|
59
|
-
});
|
|
60
|
-
log('主进程初始化完成');
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/electron/main.ts"],"names":[],"mappings":";;AAAA;;;;GAIG;AACH,uCAA8C;AAC9C,qCAA+B;AAC/B,qCAA4E;AAC5E,qCAAyC;AACzC,iCAAwC;AACxC,iCAAiD;AACjD,+BAAwC;AACxC,uCAA8C;AAC9C,2CAAqE;AAErE,IAAA,YAAG,EAAC,qBAAqB,CAAC,CAAC;AAE3B,OAAO;AACP,MAAM,UAAU,GAAG,cAAG,CAAC,yBAAyB,EAAE,CAAC;AACnD,IAAI,CAAC,UAAU,EAAE,CAAC;IAChB,IAAA,YAAG,EAAC,YAAY,CAAC,CAAC;IAClB,cAAG,CAAC,IAAI,EAAE,CAAC;AACb,CAAC;AAED,cAAG,CAAC,EAAE,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC7B,IAAA,wBAAe,GAAE,CAAC;AACpB,CAAC,CAAC,CAAC;AAEH,cAAG,CAAC,SAAS,EAAE,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE;IAC9B,IAAA,YAAG,EAAC,cAAc,CAAC,CAAC;IACpB,IAAA,qBAAe,GAAE,CAAC;IAClB,IAAA,2BAAiB,GAAE,CAAC;IACpB,IAAA,+BAAmB,GAAE,CAAC;IACtB,IAAA,qBAAc,EAAC,sBAAa,CAAC,CAAC;IAC9B,IAAA,iBAAU,EAAC,sBAAa,CAAC,CAAC;IAE1B,MAAM,IAAA,yBAAgB,GAAE,CAAC;IAEzB,0BAA0B;IAC1B,MAAM,GAAG,GAAG,IAAA,sBAAa,GAAE,CAAC;IAC5B,IAAI,GAAG,EAAE,CAAC;QACR,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,iBAAiB,EAAE,GAAG,EAAE;YAC3C,KAAK,IAAA,6BAAiB,EAAC,GAAG,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;IACL,CAAC;IAED,cAAG,CAAC,EAAE,CAAC,UAAU,EAAE,KAAK,IAAI,EAAE;QAC5B,8BAA8B;QAC9B,IAAI,wBAAa,CAAC,aAAa,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/C,MAAM,IAAA,yBAAgB,GAAE,CAAC;QAC3B,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,cAAG,CAAC,EAAE,CAAC,mBAAmB,EAAE,GAAG,EAAE;IAC/B,IAAA,YAAG,EAAC,SAAS,CAAC,CAAC;IACf,IAAA,kBAAW,GAAE,CAAC;IACd,IAAA,sBAAa,GAAE,CAAC;IAChB,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,cAAG,CAAC,IAAI,EAAE,CAAC;IACb,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,cAAG,CAAC,EAAE,CAAC,aAAa,EAAE,GAAG,EAAE;IACzB,IAAA,YAAG,EAAC,QAAQ,CAAC,CAAC;IACd,IAAA,kBAAW,GAAE,CAAC;IACd,IAAA,sBAAa,GAAE,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,IAAA,YAAG,EAAC,UAAU,CAAC,CAAC"}
|