@bolloon/bolloon-agent 0.1.1 → 0.1.2
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/bin/bolloon-cli.cjs +157 -0
- package/bin/bolloon-daemon.sh +207 -0
- package/bin/bolloon.cmd +11 -0
- package/dist/agents/constraint-layer.js +10 -15
- package/dist/agents/pi-sdk.js +433 -106
- package/dist/agents/protocol.js +82 -1
- package/dist/agents/subagent-manager.js +2 -2
- package/dist/agents/workflow-engine.js +15 -20
- package/dist/agents/workflow-pivot-loop.js +541 -0
- package/dist/bollharness/src/index.js +5 -0
- package/dist/bollharness/src/scripts/checks/check_adr_plan_numbering.js +6 -0
- package/dist/bollharness/src/scripts/checks/check_api_types.js +45 -0
- package/dist/bollharness/src/scripts/checks/check_artifact_link.js +146 -0
- package/dist/bollharness/src/scripts/checks/check_bridge_deps.js +6 -0
- package/dist/bollharness/src/scripts/checks/check_bugfix_binding.js +6 -0
- package/dist/bollharness/src/scripts/checks/check_bugfix_binding_ci.js +6 -0
- package/dist/bollharness/src/scripts/checks/check_doc_file_references.js +6 -0
- package/dist/bollharness/src/scripts/checks/check_doc_freshness.js +135 -0
- package/dist/bollharness/src/scripts/checks/check_doc_links.js +31 -0
- package/dist/bollharness/src/scripts/checks/check_file_existence_claims.js +6 -0
- package/dist/bollharness/src/scripts/checks/check_fragment_integrity.js +34 -0
- package/dist/bollharness/src/scripts/checks/check_hook_installed.js +63 -0
- package/dist/bollharness/src/scripts/checks/check_issue_closure.js +41 -0
- package/dist/bollharness/src/scripts/checks/check_mcp_parity.js +6 -0
- package/dist/bollharness/src/scripts/checks/check_security.js +48 -0
- package/dist/bollharness/src/scripts/checks/check_skill_parity.js +6 -0
- package/dist/bollharness/src/scripts/checks/check_versions.js +6 -0
- package/dist/bollharness/src/scripts/checks/finding.js +13 -0
- package/dist/bollharness/src/scripts/checks/next_decision_number.js +20 -0
- package/dist/bollharness/src/scripts/checks/regenerate_magic_docs.js +6 -0
- package/dist/bollharness/src/scripts/ci/detect_rebaseline_triggers.js +8 -0
- package/dist/bollharness/src/scripts/ci/scan_subprocess_cfg.js +8 -0
- package/dist/bollharness/src/scripts/ci/scan_verify_artifacts.js +8 -0
- package/dist/bollharness/src/scripts/ci/scan_yaml_schema.js +8 -0
- package/dist/bollharness/src/scripts/context_router.js +67 -0
- package/dist/bollharness/src/scripts/deploy-guard.js +157 -0
- package/dist/bollharness/src/scripts/guard-feedback.js +192 -0
- package/dist/bollharness/src/scripts/guard_router.js +158 -0
- package/dist/bollharness/src/scripts/hooks/_hook_output.js +6 -0
- package/dist/bollharness/src/scripts/hooks/auto-python3.js +6 -0
- package/dist/bollharness/src/scripts/hooks/deploy-progress-on-session-end.js +6 -0
- package/dist/bollharness/src/scripts/hooks/failure-analyzer.js +6 -0
- package/dist/bollharness/src/scripts/hooks/gate-judgment-inject.js +92 -0
- package/dist/bollharness/src/scripts/hooks/gate-transition-judgment.js +63 -0
- package/dist/bollharness/src/scripts/hooks/inbox-ack.js +6 -0
- package/dist/bollharness/src/scripts/hooks/inbox-inject-on-start.js +6 -0
- package/dist/bollharness/src/scripts/hooks/inbox-validate.js +6 -0
- package/dist/bollharness/src/scripts/hooks/inbox-write-ledger.js +6 -0
- package/dist/bollharness/src/scripts/hooks/initializer-agent.js +6 -0
- package/dist/bollharness/src/scripts/hooks/loop-detection.js +73 -0
- package/dist/bollharness/src/scripts/hooks/owner-guard.js +6 -0
- package/dist/bollharness/src/scripts/hooks/precompact.js +6 -0
- package/dist/bollharness/src/scripts/hooks/review-agent-gatekeeper.js +6 -0
- package/dist/bollharness/src/scripts/hooks/risk-tracker.js +108 -0
- package/dist/bollharness/src/scripts/hooks/sanitize-on-read.js +6 -0
- package/dist/bollharness/src/scripts/hooks/session-reflection.js +7 -0
- package/dist/bollharness/src/scripts/hooks/session-start-magic-docs.js +7 -0
- package/dist/bollharness/src/scripts/hooks/session-start-reset-risk.js +7 -0
- package/dist/bollharness/src/scripts/hooks/session-start-toolkit-reminder.js +7 -0
- package/dist/bollharness/src/scripts/hooks/stop-evaluator.js +157 -0
- package/dist/bollharness/src/scripts/hooks/tool-call-counter.js +6 -0
- package/dist/bollharness/src/scripts/hooks/trace-analyzer.js +10 -0
- package/dist/bollharness/src/scripts/install/install-trust-token.js +7 -0
- package/dist/bollharness/src/scripts/install/multi_project_registry.js +9 -0
- package/dist/bollharness/src/scripts/install/phase2_auto.js +21 -0
- package/dist/bollharness/src/scripts/install/pre_commit_installer.js +6 -0
- package/dist/bollharness/src/scripts/install/tier_selector.js +7 -0
- package/dist/bollharness/src/scripts/install/transcript_miner.js +7 -0
- package/dist/bollharness/src/scripts/lib/claim_patterns.js +10 -0
- package/dist/bollharness/src/scripts/lib/sanitize_patterns.js +12 -0
- package/dist/bollharness/src/scripts/sanitize.js +6 -0
- package/dist/bollharness-integration/channel-judgment-engine.js +530 -0
- package/dist/bollharness-integration/context-chain-router.js +383 -0
- package/dist/bollharness-integration/context-router-judgment.js +13 -21
- package/dist/bollharness-integration/context-router.js +22 -64
- package/dist/bollharness-integration/gate-state-machine.js +14 -19
- package/dist/bollharness-integration/gate-transition-hooks.js +16 -61
- package/dist/bollharness-integration/guard-checker.js +21 -68
- package/dist/bollharness-integration/index.js +14 -124
- package/dist/bollharness-integration/integration.js +13 -20
- package/dist/bollharness-integration/llm-judgment-engine.js +569 -0
- package/dist/bollharness-integration/skill-adapter.js +18 -64
- package/dist/cli-entry.js +261 -0
- package/dist/constraint-runtime/src/commands.js +17 -7
- package/dist/constraint-runtime/src/constraint/budget.js +1 -6
- package/dist/constraint-runtime/src/constraint/permission.js +1 -6
- package/dist/constraint-runtime/src/models.js +1 -3
- package/dist/constraint-runtime/src/tools.js +17 -7
- package/dist/constraints/index.js +1 -7
- package/dist/documents/reader.js +8 -49
- package/dist/heartbeat/DaemonManager.js +242 -0
- package/dist/heartbeat/HealthMonitor.js +285 -0
- package/dist/heartbeat/StartupVerifier.js +205 -0
- package/dist/heartbeat/Watchdog.js +168 -0
- package/dist/heartbeat/index.js +84 -0
- package/dist/heartbeat/types.js +5 -0
- package/dist/index.js +381 -28
- package/dist/llm/config-store.js +31 -57
- package/dist/llm/llm-judgment-client.js +389 -0
- package/dist/llm/pi-ai.js +9 -52
- package/dist/network/agent-network.js +46 -90
- package/dist/network/hybrid-messenger.js +125 -0
- package/dist/network/iroh-bootstrap.js +38 -0
- package/dist/network/iroh-discovery.js +145 -0
- package/dist/network/iroh-integration.js +9 -16
- package/dist/network/iroh-transport.js +10 -48
- package/dist/network/p2p.js +23 -62
- package/dist/network/storage/adapters/json-adapter.js +4 -42
- package/dist/network/storage/index.js +147 -0
- package/dist/network/storage/types.js +14 -0
- package/dist/pi-ecosystem/index.js +233 -0
- package/dist/pi-ecosystem-colony/index.js +29 -90
- package/dist/pi-ecosystem-goals/index.js +20 -74
- package/dist/pi-ecosystem-judgment/decision.js +29 -47
- package/dist/pi-ecosystem-judgment/distillation.js +16 -29
- package/dist/pi-ecosystem-judgment/human-value-store.js +13 -60
- package/dist/pi-ecosystem-judgment/index.js +21 -74
- package/dist/pi-ecosystem-judgment/value-injection.js +26 -72
- package/dist/pi-ecosystem-mcp/index.js +24 -78
- package/dist/pi-ecosystem-subagents/index.js +20 -69
- package/dist/social/ant-colony/AdaptiveHeartbeat.js +3 -8
- package/dist/social/ant-colony/PheromoneEngine.js +11 -49
- package/dist/social/ant-colony/index.js +6 -0
- package/dist/social/ant-colony/types.js +4 -8
- package/dist/social/channels/ChannelManager.js +8 -46
- package/dist/social/channels/DiapChannelBridge.js +9 -47
- package/dist/social/channels/InterestMatcher.js +2 -7
- package/dist/social/channels/channel-agent-session.js +309 -0
- package/dist/social/channels/channel-heartbeat-agent.js +494 -0
- package/dist/social/channels/diap-doc-parser.js +204 -0
- package/dist/social/channels/harness-workflow-integrator.js +446 -0
- package/dist/social/channels/index.js +9 -0
- package/dist/social/channels/types.js +3 -7
- package/dist/social/global-shared-context.js +6 -47
- package/dist/social/heartbeat.js +29 -72
- package/dist/social/persona/enhanced-persona.js +299 -0
- package/dist/web/client.js +302 -136
- package/dist/web/components/p2p/index.js +159 -9
- package/dist/web/components/p2p/p2p-connection.js +136 -0
- package/dist/web/components/p2p/p2p-manager.js +24 -0
- package/dist/web/components/p2p/p2p-store-memory.js +1 -1
- package/dist/web/components/p2p/types.js +7 -0
- package/dist/web/index.html +5 -0
- package/dist/web/style.css +118 -0
- package/package.json +12 -6
- package/scripts/build-cli.js +206 -0
- package/scripts/postinstall.js +153 -0
- package/src/agents/pi-sdk.ts +347 -28
- package/src/agents/protocol.ts +95 -1
- package/src/agents/workflow-pivot-loop.ts +674 -0
- package/src/bollharness/CLAUDE.md +73 -0
- package/src/bollharness/README.md +143 -0
- package/src/bollharness/README.zh-CN.md +131 -0
- package/src/bollharness/reference/boll-reference/scripts/hooks/stop-evaluator.md +57 -0
- package/src/bollharness/scripts/context-fragments/artifact-linkage.md +14 -0
- package/src/bollharness/scripts/context-fragments/auth-consumers.md +17 -0
- package/src/bollharness/scripts/context-fragments/bridge-constitution.md +13 -0
- package/src/bollharness/scripts/context-fragments/catalyst-distributed.md +18 -0
- package/src/bollharness/scripts/context-fragments/closure-checklist.md +13 -0
- package/src/bollharness/scripts/context-fragments/contract-consumers.md +15 -0
- package/src/bollharness/scripts/context-fragments/db-shared-structures.md +15 -0
- package/src/bollharness/scripts/context-fragments/fixed-three-layers.md +19 -0
- package/src/bollharness/scripts/context-fragments/general-dev-principles.md +11 -0
- package/src/bollharness/scripts/context-fragments/issue-first.md +8 -0
- package/src/bollharness/scripts/context-fragments/mcp-parity.md +16 -0
- package/src/bollharness/scripts/context-fragments/pi-agent-operations.md +108 -0
- package/src/bollharness/scripts/context-fragments/protocol-consumers.md +15 -0
- package/src/bollharness/scripts/context-fragments/run-events-consumers.md +15 -0
- package/src/bollharness/scripts/context-fragments/scene-fidelity.md +13 -0
- package/src/bollharness/scripts/context-fragments/truth-source-hierarchy.md +15 -0
- package/src/bollharness/scripts/context-fragments/two-language.md +15 -0
- package/src/bollharness/scripts/context-fragments/version-sources.md +14 -0
- package/src/bollharness/scripts/hooks/stop-evaluator.md +83 -0
- package/src/bollharness/templates/scaffold/CLAUDE.md +89 -0
- package/src/cli-entry.ts +304 -0
- package/src/heartbeat/DaemonManager.ts +283 -0
- package/src/heartbeat/HealthMonitor.ts +316 -0
- package/src/heartbeat/StartupVerifier.ts +223 -0
- package/src/heartbeat/Watchdog.ts +198 -0
- package/src/heartbeat/index.ts +108 -0
- package/src/heartbeat/types.ts +82 -0
- package/src/llm/config-store.ts +23 -5
- package/src/network/iroh-transport.ts +3 -3
- package/src/web/client.js +302 -136
- package/src/web/components/p2p/P2PModal.tsx +91 -3
- package/src/web/components/p2p/index.ts +171 -9
- package/src/web/components/p2p/p2p-connection.ts +153 -1
- package/src/web/components/p2p/p2p-manager.ts +39 -1
- package/src/web/components/p2p/p2p-store-memory.ts +1 -1
- package/src/web/components/p2p/p2p-tools.ts +315 -0
- package/src/web/components/p2p/types.ts +58 -0
- package/src/web/design.md +99 -0
- package/src/web/index.html +5 -0
- package/src/web/server.ts +353 -36
- package/src/web/style.css +118 -0
- package/tsconfig.cli.json +16 -0
- package/tsconfig.electron.json +1 -1
- package/tsconfig.json +1 -2
- package/dist/web/server.js +0 -1647
- package/dist/web/server.js.map +0 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
class P2PModalUI {
|
|
2
2
|
modal = null;
|
|
3
3
|
overlay = null;
|
|
4
|
+
connectedPeers = /* @__PURE__ */ new Map();
|
|
4
5
|
constructor() {
|
|
5
6
|
this.createModal();
|
|
6
7
|
}
|
|
@@ -38,22 +39,49 @@ class P2PModalUI {
|
|
|
38
39
|
}
|
|
39
40
|
async render() {
|
|
40
41
|
if (!this.modal) return;
|
|
42
|
+
await this.loadConnectionHistory();
|
|
41
43
|
let identityHtml = '<div class="p2p-loading">\u52A0\u8F7D\u4E2D...</div>';
|
|
44
|
+
let identityData = { name: "\u672A\u77E5", did: "\u672A\u77E5", cid: "\u672A\u77E5" };
|
|
42
45
|
try {
|
|
43
|
-
const
|
|
44
|
-
const
|
|
46
|
+
const irohResp = await fetch("/api/iroh/init", { method: "POST" });
|
|
47
|
+
const irohData = await irohResp.json();
|
|
48
|
+
if (irohData.cid) {
|
|
49
|
+
identityData = {
|
|
50
|
+
name: irohData.name || irohData.name?.split("-").slice(-1)[0] || "Bolloon",
|
|
51
|
+
did: irohData.did || "\u672A\u77E5",
|
|
52
|
+
cid: irohData.cid || "\u672A\u77E5",
|
|
53
|
+
nodeId: irohData.irohNodeId ? irohData.irohNodeId.substring(0, 20) + "..." : "\u672A\u77E5"
|
|
54
|
+
};
|
|
55
|
+
} else {
|
|
56
|
+
const resp = await fetch("/api/identity");
|
|
57
|
+
identityData = await resp.json();
|
|
58
|
+
identityData.cid = identityData.cid || "\u672A\u521D\u59CB\u5316";
|
|
59
|
+
identityData.nodeId = identityData.nodeId || "\u672A\u77E5";
|
|
60
|
+
}
|
|
45
61
|
identityHtml = `
|
|
46
62
|
<div class="p2p-section">
|
|
47
63
|
<h3>\u8EAB\u4EFD\u4FE1\u606F</h3>
|
|
48
64
|
<div class="p2p-info-row">
|
|
49
65
|
<span class="label">\u540D\u79F0:</span>
|
|
50
|
-
<span class="value">${this.escapeHtml(
|
|
66
|
+
<span class="value">${this.escapeHtml(identityData.name || "\u672A\u77E5")}</span>
|
|
67
|
+
</div>
|
|
68
|
+
<div class="p2p-info-row">
|
|
69
|
+
<span class="label">CID:</span>
|
|
70
|
+
<span class="value mono">${this.escapeHtml(identityData.cid || "\u672A\u77E5")}</span>
|
|
51
71
|
</div>
|
|
52
72
|
<div class="p2p-info-row">
|
|
53
73
|
<span class="label">DID:</span>
|
|
54
|
-
<span class="value mono">${this.escapeHtml(
|
|
74
|
+
<span class="value mono">${this.escapeHtml(identityData.did || "\u672A\u77E5")}</span>
|
|
75
|
+
</div>
|
|
76
|
+
<div class="p2p-info-row">
|
|
77
|
+
<span class="label">Node ID:</span>
|
|
78
|
+
<span class="value mono">${this.escapeHtml(identityData.nodeId || "\u672A\u77E5")}</span>
|
|
79
|
+
</div>
|
|
80
|
+
<div class="p2p-actions">
|
|
81
|
+
<button class="p2p-btn-secondary" id="p2p-copy-cid-btn">\u590D\u5236 CID</button>
|
|
82
|
+
<button class="p2p-btn-secondary" id="p2p-copy-did-btn">\u590D\u5236 DID</button>
|
|
83
|
+
<button class="p2p-btn-secondary" id="p2p-copy-nodeid-btn">\u590D\u5236 Node ID</button>
|
|
55
84
|
</div>
|
|
56
|
-
<button class="p2p-btn-primary" id="p2p-copy-btn">\u590D\u5236 DID</button>
|
|
57
85
|
</div>
|
|
58
86
|
`;
|
|
59
87
|
} catch {
|
|
@@ -82,6 +110,12 @@ class P2PModalUI {
|
|
|
82
110
|
</div>
|
|
83
111
|
<div id="p2p-connect-result" class="p2p-result"></div>
|
|
84
112
|
</div>
|
|
113
|
+
<div class="p2p-section">
|
|
114
|
+
<h3>\u5DF2\u8FDE\u63A5\u7684\u8282\u70B9</h3>
|
|
115
|
+
<div id="p2p-connected-peers" class="p2p-connected-peers">
|
|
116
|
+
\u6682\u65E0\u8FDE\u63A5
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
85
119
|
</div>
|
|
86
120
|
<div class="p2p-tab-content" data-tab="messages">
|
|
87
121
|
<div class="p2p-section">
|
|
@@ -106,11 +140,24 @@ class P2PModalUI {
|
|
|
106
140
|
if (tabName) this.switchTab(tabName);
|
|
107
141
|
});
|
|
108
142
|
});
|
|
109
|
-
const
|
|
110
|
-
|
|
143
|
+
const copyCidBtn = this.modal.querySelector("#p2p-copy-cid-btn");
|
|
144
|
+
copyCidBtn?.addEventListener("click", async () => {
|
|
111
145
|
try {
|
|
112
|
-
const
|
|
113
|
-
const data = await
|
|
146
|
+
const irohResp = await fetch("/api/iroh/init", { method: "POST" });
|
|
147
|
+
const data = await irohResp.json();
|
|
148
|
+
if (data.cid) {
|
|
149
|
+
await navigator.clipboard.writeText(data.cid);
|
|
150
|
+
this.showToast("CID \u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F");
|
|
151
|
+
}
|
|
152
|
+
} catch (e) {
|
|
153
|
+
console.error("\u590D\u5236\u5931\u8D25:", e);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
const copyDidBtn = this.modal.querySelector("#p2p-copy-did-btn");
|
|
157
|
+
copyDidBtn?.addEventListener("click", async () => {
|
|
158
|
+
try {
|
|
159
|
+
const irohResp = await fetch("/api/iroh/init", { method: "POST" });
|
|
160
|
+
const data = await irohResp.json();
|
|
114
161
|
if (data.did) {
|
|
115
162
|
await navigator.clipboard.writeText(data.did);
|
|
116
163
|
this.showToast("DID \u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F");
|
|
@@ -119,6 +166,19 @@ class P2PModalUI {
|
|
|
119
166
|
console.error("\u590D\u5236\u5931\u8D25:", e);
|
|
120
167
|
}
|
|
121
168
|
});
|
|
169
|
+
const copyNodeIdBtn = this.modal.querySelector("#p2p-copy-nodeid-btn");
|
|
170
|
+
copyNodeIdBtn?.addEventListener("click", async () => {
|
|
171
|
+
try {
|
|
172
|
+
const irohResp = await fetch("/api/iroh/init", { method: "POST" });
|
|
173
|
+
const data = await irohResp.json();
|
|
174
|
+
if (data.irohNodeId) {
|
|
175
|
+
await navigator.clipboard.writeText(data.irohNodeId);
|
|
176
|
+
this.showToast("Node ID \u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F");
|
|
177
|
+
}
|
|
178
|
+
} catch (e) {
|
|
179
|
+
console.error("\u590D\u5236\u5931\u8D25:", e);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
122
182
|
const connectBtn = this.modal.querySelector("#p2p-connect-btn");
|
|
123
183
|
connectBtn?.addEventListener("click", () => this.handleConnect());
|
|
124
184
|
}
|
|
@@ -149,6 +209,23 @@ class P2PModalUI {
|
|
|
149
209
|
if (data.ok) {
|
|
150
210
|
result.innerHTML = `<div class="p2p-success">\u8FDE\u63A5\u6210\u529F\uFF01\u8282\u70B9: ${this.escapeHtml(data.nodeName || cid.substring(0, 16))}...</div>`;
|
|
151
211
|
result.className = "p2p-result success";
|
|
212
|
+
input.value = "";
|
|
213
|
+
try {
|
|
214
|
+
await fetch("/api/p2p/history", {
|
|
215
|
+
method: "POST",
|
|
216
|
+
headers: { "Content-Type": "application/json" },
|
|
217
|
+
body: JSON.stringify({
|
|
218
|
+
cid,
|
|
219
|
+
// 输入的 CID 或 Node ID
|
|
220
|
+
irohNodeId: data.targetNodeId,
|
|
221
|
+
did: data.targetNodeId,
|
|
222
|
+
// 用 Node ID 作为 DID
|
|
223
|
+
name: data.nodeName || cid.substring(0, 16)
|
|
224
|
+
})
|
|
225
|
+
});
|
|
226
|
+
} catch (e) {
|
|
227
|
+
console.error("\u4FDD\u5B58\u8FDE\u63A5\u5931\u8D25:", e);
|
|
228
|
+
}
|
|
152
229
|
} else {
|
|
153
230
|
result.innerHTML = `<div class="p2p-error">${this.escapeHtml(data.error || "\u8FDE\u63A5\u5931\u8D25")}</div>`;
|
|
154
231
|
result.className = "p2p-result error";
|
|
@@ -159,6 +236,44 @@ class P2PModalUI {
|
|
|
159
236
|
result.className = "p2p-result error";
|
|
160
237
|
}
|
|
161
238
|
}
|
|
239
|
+
async loadConnectionHistory() {
|
|
240
|
+
try {
|
|
241
|
+
const resp = await fetch("/api/p2p/history");
|
|
242
|
+
const history = await resp.json();
|
|
243
|
+
this.connectedPeers.clear();
|
|
244
|
+
for (const entry of history) {
|
|
245
|
+
this.connectedPeers.set(entry.irohNodeId || entry.did, {
|
|
246
|
+
nodeId: entry.irohNodeId || entry.did,
|
|
247
|
+
name: entry.name || "Unknown",
|
|
248
|
+
time: entry.lastConnectedAt || Date.now()
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
this.updateConnectedPeersDisplay();
|
|
252
|
+
} catch (e) {
|
|
253
|
+
console.error("\u52A0\u8F7D\u8FDE\u63A5\u5386\u53F2\u5931\u8D25:", e);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
updateConnectedPeersDisplay() {
|
|
257
|
+
const container = document.getElementById("p2p-connected-peers");
|
|
258
|
+
if (!container) return;
|
|
259
|
+
if (this.connectedPeers.size === 0) {
|
|
260
|
+
container.innerHTML = '<div class="p2p-empty">\u6682\u65E0\u8FDE\u63A5</div>';
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
let html = "";
|
|
264
|
+
for (const [nodeId, info] of this.connectedPeers) {
|
|
265
|
+
const shortId = nodeId.substring(0, 16) + "...";
|
|
266
|
+
const time = new Date(info.time).toLocaleTimeString();
|
|
267
|
+
html += `
|
|
268
|
+
<div class="p2p-peer-item">
|
|
269
|
+
<span class="p2p-peer-name">${this.escapeHtml(info.name || shortId)}</span>
|
|
270
|
+
<span class="p2p-peer-id">${shortId}</span>
|
|
271
|
+
<span class="p2p-peer-time">${time}</span>
|
|
272
|
+
</div>
|
|
273
|
+
`;
|
|
274
|
+
}
|
|
275
|
+
container.innerHTML = html;
|
|
276
|
+
}
|
|
162
277
|
escapeHtml(str) {
|
|
163
278
|
const div = document.createElement("div");
|
|
164
279
|
div.textContent = str;
|
|
@@ -348,6 +463,41 @@ style.textContent = `
|
|
|
348
463
|
color: var(--text-muted, #606058);
|
|
349
464
|
}
|
|
350
465
|
.p2p-error { color: var(--error, #ef4444); }
|
|
466
|
+
.p2p-connected-peers {
|
|
467
|
+
background: var(--bg, #1a1a18);
|
|
468
|
+
border: 1px solid var(--border, #3a3a36);
|
|
469
|
+
border-radius: 8px;
|
|
470
|
+
overflow: hidden;
|
|
471
|
+
}
|
|
472
|
+
.p2p-connected-peers .p2p-empty {
|
|
473
|
+
padding: 16px;
|
|
474
|
+
text-align: center;
|
|
475
|
+
color: var(--text-muted, #606058);
|
|
476
|
+
font-size: 14px;
|
|
477
|
+
}
|
|
478
|
+
.p2p-peer-item {
|
|
479
|
+
display: flex;
|
|
480
|
+
align-items: center;
|
|
481
|
+
gap: 8px;
|
|
482
|
+
padding: 12px 16px;
|
|
483
|
+
border-bottom: 1px solid var(--border, #3a3a36);
|
|
484
|
+
}
|
|
485
|
+
.p2p-peer-item:last-child { border-bottom: none; }
|
|
486
|
+
.p2p-peer-name {
|
|
487
|
+
font-size: 14px;
|
|
488
|
+
color: var(--text, #d8d8c8);
|
|
489
|
+
min-width: 80px;
|
|
490
|
+
}
|
|
491
|
+
.p2p-peer-id {
|
|
492
|
+
flex: 1;
|
|
493
|
+
font-family: 'JetBrains Mono', monospace;
|
|
494
|
+
font-size: 12px;
|
|
495
|
+
color: var(--text-secondary, #909088);
|
|
496
|
+
}
|
|
497
|
+
.p2p-peer-time {
|
|
498
|
+
font-size: 12px;
|
|
499
|
+
color: var(--text-muted, #606058);
|
|
500
|
+
}
|
|
351
501
|
`;
|
|
352
502
|
document.head.appendChild(style);
|
|
353
503
|
const p2pModal = new P2PModalUI();
|
|
@@ -157,5 +157,141 @@ export class P2PConnectionManager {
|
|
|
157
157
|
this.reconnectTimers.clear();
|
|
158
158
|
this.peers.clear();
|
|
159
159
|
}
|
|
160
|
+
// 从 CID 解析身份
|
|
161
|
+
async resolveFromCID(cid) {
|
|
162
|
+
try {
|
|
163
|
+
const res = await fetch('/api/p2p/resolve-cid', {
|
|
164
|
+
method: 'POST',
|
|
165
|
+
headers: { 'Content-Type': 'application/json' },
|
|
166
|
+
body: JSON.stringify({ cid })
|
|
167
|
+
});
|
|
168
|
+
if (res.ok) {
|
|
169
|
+
const data = await res.json();
|
|
170
|
+
return {
|
|
171
|
+
success: true,
|
|
172
|
+
did: data.doc?.id || data.doc?.did,
|
|
173
|
+
cid: cid,
|
|
174
|
+
name: data.doc?.name,
|
|
175
|
+
peerId: data.doc?.peerId
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
return { success: false, error: 'CID 解析失败' };
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
catch (e) {
|
|
183
|
+
return { success: false, error: e.message };
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
// 获取所有持久连接
|
|
187
|
+
async getPersistentConnections() {
|
|
188
|
+
try {
|
|
189
|
+
const res = await fetch('/api/p2p/persistent-connections');
|
|
190
|
+
if (res.ok) {
|
|
191
|
+
return await res.json();
|
|
192
|
+
}
|
|
193
|
+
return [];
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
return [];
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// 切换连接状态
|
|
200
|
+
async toggleConnection(connection, enable) {
|
|
201
|
+
try {
|
|
202
|
+
if (enable) {
|
|
203
|
+
// 建立连接
|
|
204
|
+
const result = await this.connect(connection.cid);
|
|
205
|
+
if (result.success) {
|
|
206
|
+
await fetch('/api/p2p/connection-status', {
|
|
207
|
+
method: 'POST',
|
|
208
|
+
headers: { 'Content-Type': 'application/json' },
|
|
209
|
+
body: JSON.stringify({
|
|
210
|
+
id: connection.id,
|
|
211
|
+
status: 'connected',
|
|
212
|
+
channelId: connection.channelId
|
|
213
|
+
})
|
|
214
|
+
});
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
// 断开连接
|
|
221
|
+
if (connection.peerId) {
|
|
222
|
+
await this.disconnect(connection.peerId);
|
|
223
|
+
}
|
|
224
|
+
await fetch('/api/p2p/connection-status', {
|
|
225
|
+
method: 'POST',
|
|
226
|
+
headers: { 'Content-Type': 'application/json' },
|
|
227
|
+
body: JSON.stringify({
|
|
228
|
+
id: connection.id,
|
|
229
|
+
status: 'disconnected'
|
|
230
|
+
})
|
|
231
|
+
});
|
|
232
|
+
return true;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
catch {
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
// 连接并创建对话通道
|
|
240
|
+
async connectAndCreateChannel(input, onProgress) {
|
|
241
|
+
const parsed = this.parseInput(input);
|
|
242
|
+
if (parsed.type === 'invalid') {
|
|
243
|
+
return { success: false, error: parsed.error };
|
|
244
|
+
}
|
|
245
|
+
onProgress?.({ stage: 'validating', percent: 10, message: '验证输入格式...' });
|
|
246
|
+
let cid = '';
|
|
247
|
+
let did = '';
|
|
248
|
+
const value = parsed.value;
|
|
249
|
+
if (parsed.type === 'link' && typeof value !== 'string') {
|
|
250
|
+
cid = value.cid || '';
|
|
251
|
+
did = value.did || '';
|
|
252
|
+
}
|
|
253
|
+
else if (parsed.type === 'cid' && typeof value === 'string') {
|
|
254
|
+
cid = value;
|
|
255
|
+
}
|
|
256
|
+
else if (parsed.type === 'diapDoc' && typeof value !== 'string') {
|
|
257
|
+
cid = value.cid || '';
|
|
258
|
+
did = value.id || value.did || '';
|
|
259
|
+
}
|
|
260
|
+
if (!cid) {
|
|
261
|
+
return { success: false, error: '未找到 CID' };
|
|
262
|
+
}
|
|
263
|
+
// 如果没有 DID,从 CID 解析
|
|
264
|
+
if (!did) {
|
|
265
|
+
onProgress?.({ stage: 'resolving', percent: 30, message: '从 IPFS 解析身份...' });
|
|
266
|
+
const resolveResult = await this.resolveFromCID(cid);
|
|
267
|
+
if (resolveResult.success) {
|
|
268
|
+
did = resolveResult.did || '';
|
|
269
|
+
onProgress?.({ stage: 'identity_resolved', percent: 50, message: `身份解析完成: ${resolveResult.name}` });
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
// 创建对话通道
|
|
273
|
+
onProgress?.({ stage: 'creating_channel', percent: 60, message: '创建对话通道...' });
|
|
274
|
+
try {
|
|
275
|
+
const channelRes = await fetch('/api/p2p/create-channel', {
|
|
276
|
+
method: 'POST',
|
|
277
|
+
headers: { 'Content-Type': 'application/json' },
|
|
278
|
+
body: JSON.stringify({
|
|
279
|
+
peerDid: did,
|
|
280
|
+
peerName: did.substring(0, 16),
|
|
281
|
+
cid: cid,
|
|
282
|
+
peerId: ''
|
|
283
|
+
})
|
|
284
|
+
});
|
|
285
|
+
if (!channelRes.ok) {
|
|
286
|
+
return { success: false, error: '创建对话通道失败' };
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
catch (e) {
|
|
290
|
+
return { success: false, error: e.message };
|
|
291
|
+
}
|
|
292
|
+
// 执行连接
|
|
293
|
+
onProgress?.({ stage: 'connecting', percent: 80, message: '建立 P2P 连接...' });
|
|
294
|
+
return this.connect(input, onProgress);
|
|
295
|
+
}
|
|
160
296
|
}
|
|
161
297
|
export const p2pConnection = new P2PConnectionManager();
|
|
@@ -72,6 +72,30 @@ export class P2PManager {
|
|
|
72
72
|
this.connection.destroy();
|
|
73
73
|
this.messages.destroy();
|
|
74
74
|
}
|
|
75
|
+
// 获取持久连接列表
|
|
76
|
+
async getPersistentConnections() {
|
|
77
|
+
return this.connection.getPersistentConnections();
|
|
78
|
+
}
|
|
79
|
+
// 更新连接状态
|
|
80
|
+
async updateConnectionStatus(id, status, channelId) {
|
|
81
|
+
await fetch('/api/p2p/connection-status', {
|
|
82
|
+
method: 'POST',
|
|
83
|
+
headers: { 'Content-Type': 'application/json' },
|
|
84
|
+
body: JSON.stringify({ id, status, channelId })
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
// 切换连接状态
|
|
88
|
+
async toggleConnection(connection, enable) {
|
|
89
|
+
return this.connection.toggleConnection(connection, enable);
|
|
90
|
+
}
|
|
91
|
+
// CID 解析
|
|
92
|
+
async resolveFromCID(cid) {
|
|
93
|
+
return this.connection.resolveFromCID(cid);
|
|
94
|
+
}
|
|
95
|
+
// 连接并创建对话通道
|
|
96
|
+
async connectAndCreateChannel(input, onProgress) {
|
|
97
|
+
return this.connection.connectAndCreateChannel(input, onProgress);
|
|
98
|
+
}
|
|
75
99
|
}
|
|
76
100
|
// 全局单例
|
|
77
101
|
export const p2pManager = new P2PManager();
|
|
@@ -17,7 +17,7 @@ export class P2PStoreMemory {
|
|
|
17
17
|
};
|
|
18
18
|
// ==================== 连接历史 ====================
|
|
19
19
|
async addToHistory(entry) {
|
|
20
|
-
const existingIndex = this.history.findIndex(h => h.
|
|
20
|
+
const existingIndex = this.history.findIndex(h => h.cid === entry.cid);
|
|
21
21
|
if (existingIndex >= 0) {
|
|
22
22
|
this.history[existingIndex] = {
|
|
23
23
|
...this.history[existingIndex],
|
|
@@ -21,3 +21,10 @@ export var MessageStatus;
|
|
|
21
21
|
MessageStatus["FAILED"] = "failed";
|
|
22
22
|
MessageStatus["QUEUED"] = "queued";
|
|
23
23
|
})(MessageStatus || (MessageStatus = {}));
|
|
24
|
+
// 持久连接状态
|
|
25
|
+
export var PersistentConnectionStatus;
|
|
26
|
+
(function (PersistentConnectionStatus) {
|
|
27
|
+
PersistentConnectionStatus["CONNECTED"] = "connected";
|
|
28
|
+
PersistentConnectionStatus["DISCONNECTED"] = "disconnected";
|
|
29
|
+
PersistentConnectionStatus["RECONNECTING"] = "reconnecting";
|
|
30
|
+
})(PersistentConnectionStatus || (PersistentConnectionStatus = {}));
|
package/dist/web/index.html
CHANGED
|
@@ -61,6 +61,11 @@
|
|
|
61
61
|
<h1 id="channel-name">Bolloon Agent</h1>
|
|
62
62
|
</div>
|
|
63
63
|
<div class="header-right">
|
|
64
|
+
<button id="new-session-btn" class="header-action" title="新会话">
|
|
65
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
66
|
+
<path d="M12 5v14M5 12h14"></path>
|
|
67
|
+
</svg>
|
|
68
|
+
</button>
|
|
64
69
|
<button id="theme-toggle" class="theme-toggle" title="切换主题">
|
|
65
70
|
<svg class="sun-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
66
71
|
<circle cx="12" cy="12" r="5"></circle>
|
package/dist/web/style.css
CHANGED
|
@@ -594,6 +594,21 @@ body {
|
|
|
594
594
|
border-radius: 3px;
|
|
595
595
|
}
|
|
596
596
|
|
|
597
|
+
/* Channel messages container */
|
|
598
|
+
.channel-messages {
|
|
599
|
+
display: none;
|
|
600
|
+
flex: 1;
|
|
601
|
+
overflow-y: auto;
|
|
602
|
+
padding: 24px;
|
|
603
|
+
flex-direction: column;
|
|
604
|
+
gap: 20px;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
.channel-messages.active,
|
|
608
|
+
.channel-messages:not([style*="display: none"]) {
|
|
609
|
+
display: flex;
|
|
610
|
+
}
|
|
611
|
+
|
|
597
612
|
.message {
|
|
598
613
|
display: flex;
|
|
599
614
|
flex-direction: column;
|
|
@@ -3231,6 +3246,109 @@ body {
|
|
|
3231
3246
|
cursor: pointer;
|
|
3232
3247
|
}
|
|
3233
3248
|
|
|
3249
|
+
/* Persistent Peers Section */
|
|
3250
|
+
.persistent-peers-section {
|
|
3251
|
+
margin: 16px 0;
|
|
3252
|
+
padding: 12px;
|
|
3253
|
+
background: var(--bg-secondary);
|
|
3254
|
+
border: 1px solid var(--border);
|
|
3255
|
+
border-radius: var(--radius);
|
|
3256
|
+
}
|
|
3257
|
+
|
|
3258
|
+
.persistent-peers-section h4 {
|
|
3259
|
+
margin-bottom: 12px;
|
|
3260
|
+
font-size: 14px;
|
|
3261
|
+
color: var(--text);
|
|
3262
|
+
}
|
|
3263
|
+
|
|
3264
|
+
.persistent-peer-item {
|
|
3265
|
+
display: flex;
|
|
3266
|
+
align-items: center;
|
|
3267
|
+
gap: 12px;
|
|
3268
|
+
padding: 12px;
|
|
3269
|
+
border: 1px solid var(--border);
|
|
3270
|
+
border-radius: 8px;
|
|
3271
|
+
margin-bottom: 8px;
|
|
3272
|
+
background: var(--bg-primary);
|
|
3273
|
+
transition: var(--transition);
|
|
3274
|
+
}
|
|
3275
|
+
|
|
3276
|
+
.persistent-peer-item:last-child {
|
|
3277
|
+
margin-bottom: 0;
|
|
3278
|
+
}
|
|
3279
|
+
|
|
3280
|
+
.persistent-peer-item.connected {
|
|
3281
|
+
border-color: var(--success);
|
|
3282
|
+
background: rgba(76, 175, 80, 0.05);
|
|
3283
|
+
}
|
|
3284
|
+
|
|
3285
|
+
.persistent-peer-item.disconnected {
|
|
3286
|
+
opacity: 0.8;
|
|
3287
|
+
}
|
|
3288
|
+
|
|
3289
|
+
.persistent-peer-item.reconnecting {
|
|
3290
|
+
border-color: var(--warning);
|
|
3291
|
+
animation: pulse 2s infinite;
|
|
3292
|
+
}
|
|
3293
|
+
|
|
3294
|
+
@keyframes pulse {
|
|
3295
|
+
0%, 100% { opacity: 1; }
|
|
3296
|
+
50% { opacity: 0.6; }
|
|
3297
|
+
}
|
|
3298
|
+
|
|
3299
|
+
.peer-status-indicator {
|
|
3300
|
+
flex-shrink: 0;
|
|
3301
|
+
}
|
|
3302
|
+
|
|
3303
|
+
.peer-status-indicator .dot {
|
|
3304
|
+
display: block;
|
|
3305
|
+
width: 10px;
|
|
3306
|
+
height: 10px;
|
|
3307
|
+
border-radius: 50%;
|
|
3308
|
+
}
|
|
3309
|
+
|
|
3310
|
+
.peer-status-indicator .dot.online {
|
|
3311
|
+
background: var(--success);
|
|
3312
|
+
box-shadow: 0 0 6px var(--success);
|
|
3313
|
+
}
|
|
3314
|
+
|
|
3315
|
+
.peer-status-indicator .dot.offline {
|
|
3316
|
+
background: var(--text-muted);
|
|
3317
|
+
}
|
|
3318
|
+
|
|
3319
|
+
.auto-badge {
|
|
3320
|
+
display: inline-block;
|
|
3321
|
+
padding: 2px 6px;
|
|
3322
|
+
font-size: 10px;
|
|
3323
|
+
background: var(--accent);
|
|
3324
|
+
color: var(--bg-primary);
|
|
3325
|
+
border-radius: 4px;
|
|
3326
|
+
margin-left: 6px;
|
|
3327
|
+
}
|
|
3328
|
+
|
|
3329
|
+
.peer-info .peer-name {
|
|
3330
|
+
display: flex;
|
|
3331
|
+
align-items: center;
|
|
3332
|
+
font-weight: 500;
|
|
3333
|
+
}
|
|
3334
|
+
|
|
3335
|
+
.peer-info .peer-meta {
|
|
3336
|
+
font-size: 12px;
|
|
3337
|
+
color: var(--text-secondary);
|
|
3338
|
+
display: flex;
|
|
3339
|
+
gap: 12px;
|
|
3340
|
+
margin-top: 4px;
|
|
3341
|
+
}
|
|
3342
|
+
|
|
3343
|
+
.btn-danger {
|
|
3344
|
+
background: var(--error);
|
|
3345
|
+
color: white;
|
|
3346
|
+
}
|
|
3347
|
+
|
|
3348
|
+
.btn-danger:hover {
|
|
3349
|
+
background: #c62828;
|
|
3350
|
+
}
|
|
3351
|
+
|
|
3234
3352
|
/* Modal Small */
|
|
3235
3353
|
.modal-sm {
|
|
3236
3354
|
max-width: 300px !important;
|
package/package.json
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bolloon/bolloon-agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "P2P AI Document Agent
|
|
6
|
-
"main": "dist/
|
|
5
|
+
"description": "P2P AI Document Agent - 全局安装后执行 `bolloon` 启动产品",
|
|
6
|
+
"main": "dist/cli.js",
|
|
7
7
|
"author": "Bolloon Team",
|
|
8
|
+
"bin": {
|
|
9
|
+
"bolloon": "./bin/bolloon-cli.cjs"
|
|
10
|
+
},
|
|
8
11
|
"scripts": {
|
|
9
12
|
"build": "npm run build --workspaces --if-present",
|
|
10
13
|
"build:main": "tsc",
|
|
14
|
+
"build:cli": "node scripts/build-cli.js",
|
|
11
15
|
"build:web": "npx tsx scripts/build-web.ts",
|
|
12
16
|
"build:electron": "tsc -p tsconfig.electron.json",
|
|
17
|
+
"build:all": "npm run build:main && npm run build:web && npm run build:electron && npm run build:cli",
|
|
13
18
|
"start": "node dist/index.js",
|
|
14
19
|
"dev": "tsx -r dotenv/config src/index.ts",
|
|
15
20
|
"dev:web": "npm run build:web && npm run dev",
|
|
@@ -20,7 +25,8 @@
|
|
|
20
25
|
"electron:pack": "electron-builder --dir",
|
|
21
26
|
"test": "vitest run",
|
|
22
27
|
"test:watch": "vitest",
|
|
23
|
-
"test:pi-sdk": "tsx src/test/pi-sdk.test.ts"
|
|
28
|
+
"test:pi-sdk": "tsx src/test/pi-sdk.test.ts",
|
|
29
|
+
"postinstall": "node scripts/postinstall.js"
|
|
24
30
|
},
|
|
25
31
|
"workspaces": [
|
|
26
32
|
"src/constraint-runtime"
|
|
@@ -73,11 +79,11 @@
|
|
|
73
79
|
},
|
|
74
80
|
"files": [
|
|
75
81
|
"dist/**/*",
|
|
76
|
-
"
|
|
82
|
+
"bin/**/*",
|
|
77
83
|
"package.json"
|
|
78
84
|
],
|
|
79
85
|
"extraMetadata": {
|
|
80
|
-
"main": "
|
|
86
|
+
"main": "dist/electron.js",
|
|
81
87
|
"type": "commonjs"
|
|
82
88
|
},
|
|
83
89
|
"win": {
|