@bolloon/bolloon-agent 0.2.9 → 0.2.10
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
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PheromoneEngine - 信息素管理引擎
|
|
3
|
+
*
|
|
4
|
+
* 模拟蚂蚁的信息素系统,用于引导智能体发现和路由决策
|
|
5
|
+
*/
|
|
6
|
+
import * as fs from 'fs/promises';
|
|
7
|
+
import * as path from 'path';
|
|
8
|
+
import { PheromoneType, DEFAULT_PHEROMONE_CONFIG, } from './types.js';
|
|
9
|
+
export { PheromoneType };
|
|
10
|
+
const PHEROMONE_DB_PATH = path.join(process.env.HOME || '/tmp', '.bolloon', 'ant-colony', 'pheromones.json');
|
|
11
|
+
export class PheromoneEngine {
|
|
12
|
+
trails = new Map();
|
|
13
|
+
fields = new Map();
|
|
14
|
+
evaporationTimer = null;
|
|
15
|
+
saveTimer = null;
|
|
16
|
+
dirty = false;
|
|
17
|
+
async initialize() {
|
|
18
|
+
await fs.mkdir(path.dirname(PHEROMONE_DB_PATH), { recursive: true });
|
|
19
|
+
await this.load();
|
|
20
|
+
this.startEvaporation();
|
|
21
|
+
this.startAutoSave();
|
|
22
|
+
}
|
|
23
|
+
startEvaporation() {
|
|
24
|
+
this.evaporationTimer = setInterval(() => {
|
|
25
|
+
this.evaporate();
|
|
26
|
+
}, DEFAULT_PHEROMONE_CONFIG.evaporationInterval);
|
|
27
|
+
}
|
|
28
|
+
startAutoSave() {
|
|
29
|
+
this.saveTimer = setInterval(() => {
|
|
30
|
+
if (this.dirty) {
|
|
31
|
+
this.save().catch(console.error);
|
|
32
|
+
this.dirty = false;
|
|
33
|
+
}
|
|
34
|
+
}, 30000);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 放置信息素
|
|
38
|
+
*/
|
|
39
|
+
async deposit(type, sourceDid, targetDid, strength = 0.5, options) {
|
|
40
|
+
const key = this.getTrailKey(type, sourceDid, targetDid);
|
|
41
|
+
const existing = this.trails.get(key);
|
|
42
|
+
const newStrength = existing
|
|
43
|
+
? Math.min(1, existing.strength + strength * 0.3)
|
|
44
|
+
: Math.min(1, strength);
|
|
45
|
+
const trail = {
|
|
46
|
+
id: key,
|
|
47
|
+
type,
|
|
48
|
+
sourceDid,
|
|
49
|
+
targetDid,
|
|
50
|
+
strength: newStrength,
|
|
51
|
+
decayRate: DEFAULT_PHEROMONE_CONFIG.decayRate,
|
|
52
|
+
createdAt: existing?.createdAt || Date.now(),
|
|
53
|
+
lastUpdate: Date.now(),
|
|
54
|
+
capability: options?.capability,
|
|
55
|
+
qualityScore: options?.qualityScore,
|
|
56
|
+
};
|
|
57
|
+
this.trails.set(key, trail);
|
|
58
|
+
this.dirty = true;
|
|
59
|
+
if (options?.capability) {
|
|
60
|
+
this.updateField(type, targetDid, options.capability);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* 读取某方向的信息素强度
|
|
65
|
+
*/
|
|
66
|
+
getStrength(type, targetDid) {
|
|
67
|
+
let totalStrength = 0;
|
|
68
|
+
let count = 0;
|
|
69
|
+
for (const trail of this.trails.values()) {
|
|
70
|
+
if (trail.type === type && trail.targetDid === targetDid) {
|
|
71
|
+
totalStrength += trail.strength;
|
|
72
|
+
count++;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return count > 0 ? totalStrength / count : 0;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* 查询特定能力的最佳节点
|
|
79
|
+
*/
|
|
80
|
+
queryByCapability(capability, limit = 5) {
|
|
81
|
+
const field = this.fields.get(capability);
|
|
82
|
+
if (!field)
|
|
83
|
+
return [];
|
|
84
|
+
const candidates = [];
|
|
85
|
+
for (const trail of this.trails.values()) {
|
|
86
|
+
if (trail.type === PheromoneType.CAPABILITY &&
|
|
87
|
+
trail.capability?.includes(capability)) {
|
|
88
|
+
const score = trail.strength * (trail.qualityScore || 0.5);
|
|
89
|
+
candidates.push({ did: trail.targetDid, strength: score });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
candidates.sort((a, b) => b.strength - a.strength);
|
|
93
|
+
return candidates.slice(0, limit).map((c) => c.did);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* 获取到达某节点的最佳下一跳
|
|
97
|
+
*/
|
|
98
|
+
getNextHop(targetDid, excludeDids = []) {
|
|
99
|
+
let bestHop = null;
|
|
100
|
+
let bestStrength = 0;
|
|
101
|
+
for (const trail of this.trails.values()) {
|
|
102
|
+
if (trail.targetDid === targetDid && trail.strength > bestStrength) {
|
|
103
|
+
if (!excludeDids.includes(trail.sourceDid)) {
|
|
104
|
+
bestHop = trail.sourceDid;
|
|
105
|
+
bestStrength = trail.strength;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return bestHop;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* 获取所有已知节点及其信息素强度
|
|
113
|
+
*/
|
|
114
|
+
getAllNodeStrengths() {
|
|
115
|
+
const result = new Map();
|
|
116
|
+
for (const trail of this.trails.values()) {
|
|
117
|
+
const current = result.get(trail.targetDid) || 0;
|
|
118
|
+
result.set(trail.targetDid, Math.max(current, trail.strength));
|
|
119
|
+
}
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* 获取信息素统计
|
|
124
|
+
*/
|
|
125
|
+
getStats() {
|
|
126
|
+
let totalStrength = 0;
|
|
127
|
+
for (const trail of this.trails.values()) {
|
|
128
|
+
totalStrength += trail.strength;
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
totalTrails: this.trails.size,
|
|
132
|
+
avgStrength: this.trails.size > 0 ? totalStrength / this.trails.size : 0,
|
|
133
|
+
capabilityCount: this.fields.size,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
getTrailKey(type, source, target) {
|
|
137
|
+
return `${type}:${source}:${target}`;
|
|
138
|
+
}
|
|
139
|
+
updateField(type, targetDid, capability) {
|
|
140
|
+
if (!capability)
|
|
141
|
+
return;
|
|
142
|
+
for (const cap of capability) {
|
|
143
|
+
let field = this.fields.get(cap);
|
|
144
|
+
if (!field) {
|
|
145
|
+
field = {
|
|
146
|
+
capability: cap,
|
|
147
|
+
avgStrength: 0,
|
|
148
|
+
nodeCount: 0,
|
|
149
|
+
lastUpdate: Date.now(),
|
|
150
|
+
};
|
|
151
|
+
this.fields.set(cap, field);
|
|
152
|
+
}
|
|
153
|
+
const trails = Array.from(this.trails.values()).filter((t) => t.type === type && t.capability?.includes(cap));
|
|
154
|
+
field.avgStrength =
|
|
155
|
+
trails.reduce((sum, t) => sum + t.strength, 0) / (trails.length || 1);
|
|
156
|
+
field.nodeCount = new Set(trails.map((t) => t.targetDid)).size;
|
|
157
|
+
field.lastUpdate = Date.now();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
evaporate() {
|
|
161
|
+
const now = Date.now();
|
|
162
|
+
const toDelete = [];
|
|
163
|
+
for (const [key, trail] of this.trails.entries()) {
|
|
164
|
+
const ageHours = (now - trail.lastUpdate) / (1000 * 60 * 60);
|
|
165
|
+
const decayFactor = Math.pow(1 - trail.decayRate, ageHours);
|
|
166
|
+
trail.strength = trail.strength * decayFactor;
|
|
167
|
+
if (trail.strength < DEFAULT_PHEROMONE_CONFIG.minStrength ||
|
|
168
|
+
now - trail.createdAt > DEFAULT_PHEROMONE_CONFIG.maxTrailAge) {
|
|
169
|
+
toDelete.push(key);
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
trail.lastUpdate = now;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
for (const key of toDelete) {
|
|
176
|
+
this.trails.delete(key);
|
|
177
|
+
}
|
|
178
|
+
if (toDelete.length > 0) {
|
|
179
|
+
this.dirty = true;
|
|
180
|
+
this.save().catch(console.error);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
async save() {
|
|
184
|
+
try {
|
|
185
|
+
const data = {
|
|
186
|
+
trails: Array.from(this.trails.values()),
|
|
187
|
+
fields: Array.from(this.fields.entries()),
|
|
188
|
+
};
|
|
189
|
+
await fs.writeFile(PHEROMONE_DB_PATH, JSON.stringify(data, null, 2));
|
|
190
|
+
}
|
|
191
|
+
catch (e) {
|
|
192
|
+
console.warn('[PheromoneEngine] Save failed:', e);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
async load() {
|
|
196
|
+
try {
|
|
197
|
+
const data = await fs.readFile(PHEROMONE_DB_PATH, 'utf-8');
|
|
198
|
+
const parsed = JSON.parse(data);
|
|
199
|
+
this.trails.clear();
|
|
200
|
+
for (const t of parsed.trails || []) {
|
|
201
|
+
this.trails.set(t.id, t);
|
|
202
|
+
}
|
|
203
|
+
this.fields.clear();
|
|
204
|
+
for (const [cap, field] of parsed.fields || []) {
|
|
205
|
+
this.fields.set(cap, field);
|
|
206
|
+
}
|
|
207
|
+
console.log(`[PheromoneEngine] Loaded ${this.trails.size} trails, ${this.fields.size} fields`);
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
console.log('[PheromoneEngine] No existing pheromone data, starting fresh');
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
shutdown() {
|
|
214
|
+
if (this.evaporationTimer) {
|
|
215
|
+
clearInterval(this.evaporationTimer);
|
|
216
|
+
}
|
|
217
|
+
if (this.saveTimer) {
|
|
218
|
+
clearInterval(this.saveTimer);
|
|
219
|
+
}
|
|
220
|
+
if (this.dirty) {
|
|
221
|
+
this.save()
|
|
222
|
+
.then(() => console.log('[PheromoneEngine] Saved on shutdown'))
|
|
223
|
+
.catch(console.error);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
export const pheromoneEngine = new PheromoneEngine();
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ant Colony Module - 蚁群心跳系统核心模块
|
|
3
|
+
*/
|
|
4
|
+
export { PheromoneType, DEFAULT_PHEROMONE_CONFIG, DEFAULT_ADAPTIVE_CONFIG, } from './types.js';
|
|
5
|
+
export { PheromoneEngine, pheromoneEngine } from './PheromoneEngine.js';
|
|
6
|
+
export { AdaptiveHeartbeat } from './AdaptiveHeartbeat.js';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ant Colony Types - 信息素系统类型定义
|
|
3
|
+
*/
|
|
4
|
+
export var PheromoneType;
|
|
5
|
+
(function (PheromoneType) {
|
|
6
|
+
PheromoneType["DISCOVERY"] = "discovery";
|
|
7
|
+
PheromoneType["CAPABILITY"] = "capability";
|
|
8
|
+
})(PheromoneType || (PheromoneType = {}));
|
|
9
|
+
export const DEFAULT_PHEROMONE_CONFIG = {
|
|
10
|
+
decayRate: 0.05,
|
|
11
|
+
evaporationInterval: 5 * 60 * 1000,
|
|
12
|
+
maxTrailAge: 24 * 60 * 60 * 1000,
|
|
13
|
+
minStrength: 0.05,
|
|
14
|
+
maxStrength: 1.0,
|
|
15
|
+
};
|
|
16
|
+
export const DEFAULT_ADAPTIVE_CONFIG = {
|
|
17
|
+
minInterval: 10 * 1000,
|
|
18
|
+
maxInterval: 120 * 1000,
|
|
19
|
+
baseInterval: 30 * 1000,
|
|
20
|
+
lowActivityThreshold: 0.5,
|
|
21
|
+
highActivityThreshold: 5,
|
|
22
|
+
pheromoneBoostFactor: 0.3,
|
|
23
|
+
discoveryBoostFactor: 0.4,
|
|
24
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI + 判断力注入 测试
|
|
3
|
+
* 验证 AI 调用和价值观注入功能
|
|
4
|
+
*/
|
|
5
|
+
import { createAgentSession } from '../agents/pi-sdk.js';
|
|
6
|
+
import { generateValueInjection } from '../pi-ecosystem-judgment/value-injection.js';
|
|
7
|
+
import { storeHumanJudgment, initializeValueStore, getValueStats } from '../pi-ecosystem-judgment/human-value-store.js';
|
|
8
|
+
async function main() {
|
|
9
|
+
console.log('╔═══════════════════════════════════════════════════╗');
|
|
10
|
+
console.log('║ AI + 判断力注入测试 ║');
|
|
11
|
+
console.log('╚═══════════════════════════════════════════════════╝');
|
|
12
|
+
// 1. 初始化
|
|
13
|
+
console.log('\n[1] 初始化...');
|
|
14
|
+
await initializeValueStore();
|
|
15
|
+
console.log(' ✅ 判断力存储就绪');
|
|
16
|
+
// 2. 存储一些测试判断
|
|
17
|
+
console.log('\n[2] 存储测试判断...');
|
|
18
|
+
await storeHumanJudgment({
|
|
19
|
+
decision: '代码安全性比性能更重要',
|
|
20
|
+
decision_type: 'approve',
|
|
21
|
+
reasons: ['防止被攻击', '用户数据保护'],
|
|
22
|
+
values_derived: [
|
|
23
|
+
{ category: 'safety', value: 'security-first', weight: 0.9 }
|
|
24
|
+
],
|
|
25
|
+
context: {
|
|
26
|
+
domain: 'code',
|
|
27
|
+
complexity: 'moderate',
|
|
28
|
+
stakes: 'high',
|
|
29
|
+
time_pressure: 'low'
|
|
30
|
+
},
|
|
31
|
+
outcome: { approved: true },
|
|
32
|
+
metadata: {
|
|
33
|
+
source: 'explicit',
|
|
34
|
+
confidence: 0.85,
|
|
35
|
+
revisable: true
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
console.log(' ✅ 判断已存储');
|
|
39
|
+
// 3. 查看统计
|
|
40
|
+
console.log('\n[3] 判断力统计...');
|
|
41
|
+
const stats = await getValueStats();
|
|
42
|
+
console.log(` 总判断数: ${stats.total_judgments}`);
|
|
43
|
+
console.log(` 顶级价值观: ${stats.top_values.slice(0, 3).map(v => v.value).join(', ')}`);
|
|
44
|
+
// 4. 生成价值观注入
|
|
45
|
+
console.log('\n[4] 生成价值观注入...');
|
|
46
|
+
const injection = await generateValueInjection('代码安全问题', {
|
|
47
|
+
mode: 'standard',
|
|
48
|
+
maxTokens: 400,
|
|
49
|
+
includeExamples: true,
|
|
50
|
+
includeRules: true
|
|
51
|
+
});
|
|
52
|
+
console.log(` 注入内容长度: ${injection.length} 字符`);
|
|
53
|
+
if (injection) {
|
|
54
|
+
console.log(' ✅ 价值观注入已生成');
|
|
55
|
+
}
|
|
56
|
+
// 5. 调用 AI
|
|
57
|
+
console.log('\n[5] 调用 AI...');
|
|
58
|
+
const session = await createAgentSession({ cwd: process.cwd() });
|
|
59
|
+
const prompt = injection
|
|
60
|
+
? `${injection}
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
【当前问题】
|
|
64
|
+
用户问:如何确保 API 接口的安全性?
|
|
65
|
+
|
|
66
|
+
请基于上面的价值观回复用户。`
|
|
67
|
+
: '用户问:如何确保 API 接口的安全性?请给出建议。';
|
|
68
|
+
console.log('\n[6] 发送请求到 AI...');
|
|
69
|
+
const response = await session.prompt(prompt);
|
|
70
|
+
console.log('\n═══════════════════════════════════════════════════════');
|
|
71
|
+
console.log(' AI 回复:');
|
|
72
|
+
console.log('═══════════════════════════════════════════════════════');
|
|
73
|
+
console.log(response);
|
|
74
|
+
console.log('═══════════════════════════════════════════════════════\n');
|
|
75
|
+
console.log('✅ 测试完成!');
|
|
76
|
+
}
|
|
77
|
+
main().catch(e => {
|
|
78
|
+
console.error('❌ 测试失败:', e);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
});
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bollharness Integration Tests - Standalone Component Tests
|
|
3
|
+
*
|
|
4
|
+
* These tests verify the core bollharness integration components
|
|
5
|
+
* without requiring full constraint-runtime dependency chain.
|
|
6
|
+
*/
|
|
7
|
+
import { describe, it, expect } from 'vitest';
|
|
8
|
+
const GATE_CONFIGS = {
|
|
9
|
+
0: { entryCondition: '用户提出需求', requiredArtifact: '问题陈述', requiredNextSkill: 'arch', isReviewGate: false },
|
|
10
|
+
1: { entryCondition: 'Gate 0 产物存在', requiredArtifact: 'ADR草稿', requiredNextSkill: 'arch', isReviewGate: false },
|
|
11
|
+
2: { entryCondition: 'ADR草稿完成', requiredArtifact: '审查报告', requiredNextSkill: 'review', requiredReviewSubstrate: 'ref-review-sop.md', isReviewGate: true },
|
|
12
|
+
3: { entryCondition: 'Gate 2 PASS', requiredArtifact: 'PLAN文档', requiredNextSkill: 'harness-eng', isReviewGate: false },
|
|
13
|
+
4: { entryCondition: 'PLAN vN-final冻结', requiredArtifact: '审查报告', requiredNextSkill: 'review', requiredReviewSubstrate: 'ref-review-sop.md', isReviewGate: true },
|
|
14
|
+
5: { entryCondition: 'Gate 4 PASS', requiredArtifact: 'WP拆分+TASK.md', requiredNextSkill: 'task-arch', isReviewGate: false },
|
|
15
|
+
6: { entryCondition: '全部TASK.md完成', requiredArtifact: '审查报告', requiredNextSkill: 'review', requiredReviewSubstrate: 'ref-review-sop.md', isReviewGate: true },
|
|
16
|
+
7: { entryCondition: 'Gate 6 PASS', requiredArtifact: '代码+LOG.md', requiredNextSkill: 'harness-eng', isReviewGate: false },
|
|
17
|
+
8: { entryCondition: '全部WP代码+LOG.md存在', requiredArtifact: '审查报告', requiredNextSkill: 'harness-eng-test', requiredReviewSubstrate: 'ref-review-sop.md', isReviewGate: true },
|
|
18
|
+
};
|
|
19
|
+
describe('GateStateMachine', () => {
|
|
20
|
+
let currentGate = 0;
|
|
21
|
+
let artifacts = new Map();
|
|
22
|
+
describe('initialization', () => {
|
|
23
|
+
it('should start at gate 0', () => {
|
|
24
|
+
currentGate = 0;
|
|
25
|
+
expect(currentGate).toBe(0);
|
|
26
|
+
});
|
|
27
|
+
it('should have correct gate 0 config', () => {
|
|
28
|
+
const config = GATE_CONFIGS[0];
|
|
29
|
+
expect(config.requiredArtifact).toBeDefined();
|
|
30
|
+
expect(config.isReviewGate).toBe(false);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
describe('gate configs', () => {
|
|
34
|
+
it('should have 9 gates defined', () => {
|
|
35
|
+
expect(Object.keys(GATE_CONFIGS).length).toBe(9);
|
|
36
|
+
});
|
|
37
|
+
it('should have 4 review gates (2,4,6,8)', () => {
|
|
38
|
+
expect(GATE_CONFIGS[2].isReviewGate).toBe(true);
|
|
39
|
+
expect(GATE_CONFIGS[4].isReviewGate).toBe(true);
|
|
40
|
+
expect(GATE_CONFIGS[6].isReviewGate).toBe(true);
|
|
41
|
+
expect(GATE_CONFIGS[8].isReviewGate).toBe(true);
|
|
42
|
+
});
|
|
43
|
+
it('should have correct next skill for each gate', () => {
|
|
44
|
+
expect(GATE_CONFIGS[0].requiredNextSkill).toBe('arch');
|
|
45
|
+
expect(GATE_CONFIGS[5].requiredNextSkill).toBe('task-arch');
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
describe('artifacts', () => {
|
|
49
|
+
it('should be able to submit artifacts', () => {
|
|
50
|
+
artifacts.set('test', { data: 'test' });
|
|
51
|
+
expect(artifacts.has('test')).toBe(true);
|
|
52
|
+
});
|
|
53
|
+
it('should retrieve submitted artifacts', () => {
|
|
54
|
+
artifacts.set('adr', { content: 'ADR draft' });
|
|
55
|
+
const artifact = artifacts.get('adr');
|
|
56
|
+
expect(artifact).toBeDefined();
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
// ==================== Guard Router Tests ====================
|
|
61
|
+
const GUARD_MAP = {
|
|
62
|
+
'src/agents/': ['check_api_types', 'check_skill_parity'],
|
|
63
|
+
'src/documents/': ['check_doc_freshness', 'check_api_types'],
|
|
64
|
+
'src/network/': ['check_api_types', 'check_versions'],
|
|
65
|
+
'docs/': ['check_doc_freshness', 'check_doc_links'],
|
|
66
|
+
'CLAUDE.md': ['check_doc_freshness', 'check_artifact_link'],
|
|
67
|
+
'docs/decisions/': ['check_artifact_link', 'check_versions'],
|
|
68
|
+
'src/test/': ['check_api_types', 'check_versions'],
|
|
69
|
+
};
|
|
70
|
+
function route(filePath) {
|
|
71
|
+
const matched = [];
|
|
72
|
+
const sortedPatterns = Object.keys(GUARD_MAP).sort((a, b) => b.length - a.length);
|
|
73
|
+
for (const pattern of sortedPatterns) {
|
|
74
|
+
if (filePath.startsWith(pattern) || filePath === pattern.replace(/\/$/, '')) {
|
|
75
|
+
matched.push(...GUARD_MAP[pattern]);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return [...new Set(matched)];
|
|
79
|
+
}
|
|
80
|
+
describe('GuardRouter', () => {
|
|
81
|
+
describe('routing', () => {
|
|
82
|
+
it('should route agents path to check_api_types', () => {
|
|
83
|
+
const guards = route('src/agents/pi-sdk.ts');
|
|
84
|
+
expect(guards).toContain('check_api_types');
|
|
85
|
+
});
|
|
86
|
+
it('should route docs path to doc freshness', () => {
|
|
87
|
+
const guards = route('docs/guide.md');
|
|
88
|
+
expect(guards).toContain('check_doc_freshness');
|
|
89
|
+
});
|
|
90
|
+
it('should route decisions to artifact link check', () => {
|
|
91
|
+
const guards = route('docs/decisions/adr-001.md');
|
|
92
|
+
expect(guards).toContain('check_artifact_link');
|
|
93
|
+
});
|
|
94
|
+
it('should route test files to version check', () => {
|
|
95
|
+
const guards = route('src/test/pi-sdk.test.ts');
|
|
96
|
+
expect(guards).toContain('check_versions');
|
|
97
|
+
});
|
|
98
|
+
it('should return empty array for unknown paths', () => {
|
|
99
|
+
const guards = route('src/unknown/file.ts');
|
|
100
|
+
expect(guards.length).toBe(0);
|
|
101
|
+
});
|
|
102
|
+
it('should handle CLAUDE.md special case', () => {
|
|
103
|
+
const guards = route('CLAUDE.md');
|
|
104
|
+
expect(guards).toContain('check_doc_freshness');
|
|
105
|
+
expect(guards).toContain('check_artifact_link');
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
describe('deduplication', () => {
|
|
109
|
+
it('should deduplicate guard names', () => {
|
|
110
|
+
const guards = route('src/agents/pi-sdk.ts');
|
|
111
|
+
const uniqueGuards = [...new Set(guards)];
|
|
112
|
+
expect(guards.length).toBe(uniqueGuards.length);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
// ==================== Context Router Tests ====================
|
|
117
|
+
const CONTEXT_MAP = {
|
|
118
|
+
'src/agents/': ['agent-architecture', 'multi-agent-patterns'],
|
|
119
|
+
'src/documents/': ['document-processing', 'parser-patterns'],
|
|
120
|
+
'src/network/': ['p2p-protocols', 'connection-patterns'],
|
|
121
|
+
'docs/': ['documentation-standards'],
|
|
122
|
+
'docs/decisions/': ['decision-tracking', 'adr-patterns'],
|
|
123
|
+
'src/test/': ['testing-patterns', 'quality-standards'],
|
|
124
|
+
'CLAUDE.md': ['project-governance', 'truth-source-hierarchy'],
|
|
125
|
+
};
|
|
126
|
+
const FALLBACK_FRAGMENTS = ['general-dev-principles', 'code-quality'];
|
|
127
|
+
function match(filePath) {
|
|
128
|
+
if (!filePath)
|
|
129
|
+
return [];
|
|
130
|
+
const normalized = filePath.replace(/\\/g, '/');
|
|
131
|
+
const matched = [];
|
|
132
|
+
const sortedPatterns = Object.keys(CONTEXT_MAP).sort((a, b) => b.length - a.length);
|
|
133
|
+
for (const pattern of sortedPatterns) {
|
|
134
|
+
if (normalized.startsWith(pattern) || normalized.endsWith(pattern)) {
|
|
135
|
+
matched.push(...CONTEXT_MAP[pattern]);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return [...new Set(matched)];
|
|
139
|
+
}
|
|
140
|
+
describe('ContextRouter', () => {
|
|
141
|
+
describe('matching', () => {
|
|
142
|
+
it('should match agents path', () => {
|
|
143
|
+
const fragments = match('src/agents/protocol.ts');
|
|
144
|
+
expect(fragments).toContain('agent-architecture');
|
|
145
|
+
expect(fragments).toContain('multi-agent-patterns');
|
|
146
|
+
});
|
|
147
|
+
it('should match docs path', () => {
|
|
148
|
+
const fragments = match('docs/api.md');
|
|
149
|
+
expect(fragments).toContain('documentation-standards');
|
|
150
|
+
});
|
|
151
|
+
it('should match decisions path', () => {
|
|
152
|
+
const fragments = match('docs/decisions/adr-001.md');
|
|
153
|
+
expect(fragments).toContain('decision-tracking');
|
|
154
|
+
expect(fragments).toContain('adr-patterns');
|
|
155
|
+
});
|
|
156
|
+
it('should match CLAUDE.md', () => {
|
|
157
|
+
const fragments = match('CLAUDE.md');
|
|
158
|
+
expect(fragments).toContain('project-governance');
|
|
159
|
+
});
|
|
160
|
+
it('should return empty for invalid paths', () => {
|
|
161
|
+
const fragments = match('');
|
|
162
|
+
expect(fragments.length).toBe(0);
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
describe('fallback fragments', () => {
|
|
166
|
+
it('should have fallback fragments defined', () => {
|
|
167
|
+
expect(FALLBACK_FRAGMENTS).toContain('general-dev-principles');
|
|
168
|
+
expect(FALLBACK_FRAGMENTS).toContain('code-quality');
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
// Mock skills for testing
|
|
173
|
+
const skills = {
|
|
174
|
+
arch: {
|
|
175
|
+
name: 'arch',
|
|
176
|
+
description: 'Project architect. Architecture decisions and boundary freezing.',
|
|
177
|
+
async execute(params) {
|
|
178
|
+
const essence = `Core challenge: ${params.task || 'unspecified'}`;
|
|
179
|
+
const tensions = ['Simplicity vs Flexibility', 'Performance vs Maintainability'];
|
|
180
|
+
const alternatives = [
|
|
181
|
+
{ name: 'Option A', tradeoffs: ['Fast', 'Limited'], recommendation: 'MVP' },
|
|
182
|
+
{ name: 'Option B', tradeoffs: ['More work', 'Extensible'], recommendation: 'Long-term' }
|
|
183
|
+
];
|
|
184
|
+
return JSON.stringify({ essence, tensions, alternatives }, null, 2);
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
lead: {
|
|
188
|
+
name: 'lead',
|
|
189
|
+
description: 'Development workflow commander. Fail-closed state machine.',
|
|
190
|
+
async execute(params) {
|
|
191
|
+
const action = params.action;
|
|
192
|
+
if (action === 'get_gate') {
|
|
193
|
+
return JSON.stringify({ current_gate: 0, gate_name: 'Problem Lock', required_artifact: '问题陈述' }, null, 2);
|
|
194
|
+
}
|
|
195
|
+
if (action === 'classify') {
|
|
196
|
+
const desc = params.description || '';
|
|
197
|
+
const isPolicy = desc.includes('policy');
|
|
198
|
+
const isContract = desc.includes('API') || desc.includes('contract');
|
|
199
|
+
return JSON.stringify({
|
|
200
|
+
classification: isPolicy ? 'policy' : isContract ? 'contract' : 'implementation',
|
|
201
|
+
fast_track: !isPolicy && !isContract
|
|
202
|
+
}, null, 2);
|
|
203
|
+
}
|
|
204
|
+
return JSON.stringify({ current_gate: 0 });
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
task_arch: {
|
|
208
|
+
name: 'task-arch',
|
|
209
|
+
description: 'Task decomposition. Breaks down PLAN into work packages.',
|
|
210
|
+
async execute(params) {
|
|
211
|
+
const workPackages = [
|
|
212
|
+
{ id: 'WP-1', description: 'Core implementation', files: ['src/agents/*.ts'] },
|
|
213
|
+
{ id: 'WP-2', description: 'Network layer', files: ['src/network/*.ts'] }
|
|
214
|
+
];
|
|
215
|
+
return JSON.stringify({ workPackages }, null, 2);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
describe('Skills', () => {
|
|
220
|
+
describe('arch skill', () => {
|
|
221
|
+
it('should have correct name and description', () => {
|
|
222
|
+
expect(skills.arch.name).toBe('arch');
|
|
223
|
+
expect(skills.arch.description).toContain('architect');
|
|
224
|
+
});
|
|
225
|
+
it('should execute and return analysis', async () => {
|
|
226
|
+
const result = await skills.arch.execute({ task: 'design new feature' });
|
|
227
|
+
const parsed = JSON.parse(result);
|
|
228
|
+
expect(parsed.essence).toBeDefined();
|
|
229
|
+
expect(parsed.tensions).toHaveLength(2);
|
|
230
|
+
expect(parsed.alternatives).toHaveLength(2);
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
describe('lead skill', () => {
|
|
234
|
+
it('should have correct name', () => {
|
|
235
|
+
expect(skills.lead.name).toBe('lead');
|
|
236
|
+
});
|
|
237
|
+
it('should get gate pack', async () => {
|
|
238
|
+
const result = await skills.lead.execute({ action: 'get_gate' });
|
|
239
|
+
const parsed = JSON.parse(result);
|
|
240
|
+
expect(parsed.current_gate).toBe(0);
|
|
241
|
+
});
|
|
242
|
+
it('should classify policy changes', async () => {
|
|
243
|
+
const result = await skills.lead.execute({ action: 'classify', description: 'change policy boundary' });
|
|
244
|
+
const parsed = JSON.parse(result);
|
|
245
|
+
expect(parsed.classification).toBe('policy');
|
|
246
|
+
});
|
|
247
|
+
it('should classify contract changes', async () => {
|
|
248
|
+
const result = await skills.lead.execute({ action: 'classify', description: 'change API contract' });
|
|
249
|
+
const parsed = JSON.parse(result);
|
|
250
|
+
expect(parsed.classification).toBe('contract');
|
|
251
|
+
});
|
|
252
|
+
it('should classify implementation changes as fast-track eligible', async () => {
|
|
253
|
+
const result = await skills.lead.execute({ action: 'classify', description: 'fix bug' });
|
|
254
|
+
const parsed = JSON.parse(result);
|
|
255
|
+
expect(parsed.classification).toBe('implementation');
|
|
256
|
+
expect(parsed.fast_track).toBe(true);
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
describe('task-arch skill', () => {
|
|
260
|
+
it('should decompose plan into work packages', async () => {
|
|
261
|
+
const result = await skills.task_arch.execute({ plan: 'implement feature' });
|
|
262
|
+
const parsed = JSON.parse(result);
|
|
263
|
+
expect(parsed.workPackages).toHaveLength(2);
|
|
264
|
+
expect(parsed.workPackages[0].id).toBe('WP-1');
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
// ==================== Change Classification Tests ====================
|
|
269
|
+
describe('Change Classification', () => {
|
|
270
|
+
function classifyChange(description) {
|
|
271
|
+
const isPolicy = description.includes('policy') || description.includes('boundary');
|
|
272
|
+
const isContract = description.includes('API') || description.includes('contract') || description.includes('schema');
|
|
273
|
+
const isImplementation = !isPolicy && !isContract;
|
|
274
|
+
return {
|
|
275
|
+
classification: isPolicy ? 'policy' : isContract ? 'contract' : 'implementation',
|
|
276
|
+
fast_track: isImplementation
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
it('should classify policy changes', () => {
|
|
280
|
+
const result = classifyChange('change policy boundary');
|
|
281
|
+
expect(result.classification).toBe('policy');
|
|
282
|
+
expect(result.fast_track).toBe(false);
|
|
283
|
+
});
|
|
284
|
+
it('should classify contract changes', () => {
|
|
285
|
+
const result = classifyChange('change API contract');
|
|
286
|
+
expect(result.classification).toBe('contract');
|
|
287
|
+
expect(result.fast_track).toBe(false);
|
|
288
|
+
});
|
|
289
|
+
it('should classify implementation changes', () => {
|
|
290
|
+
const result = classifyChange('fix bug in code');
|
|
291
|
+
expect(result.classification).toBe('implementation');
|
|
292
|
+
expect(result.fast_track).toBe(true);
|
|
293
|
+
});
|
|
294
|
+
it('should classify schema changes as contract', () => {
|
|
295
|
+
const result = classifyChange('update database schema');
|
|
296
|
+
expect(result.classification).toBe('contract');
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
// ==================== Integration Configuration Tests ====================
|
|
300
|
+
describe('BollharnessConfig', () => {
|
|
301
|
+
function createDefaultConfig() {
|
|
302
|
+
return {
|
|
303
|
+
enabled: true,
|
|
304
|
+
guardsEnabled: true,
|
|
305
|
+
contextEnabled: true,
|
|
306
|
+
skillsEnabled: true,
|
|
307
|
+
gatesEnabled: true,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
it('should have default config with all features enabled', () => {
|
|
311
|
+
const config = createDefaultConfig();
|
|
312
|
+
expect(config.enabled).toBe(true);
|
|
313
|
+
expect(config.guardsEnabled).toBe(true);
|
|
314
|
+
expect(config.contextEnabled).toBe(true);
|
|
315
|
+
expect(config.skillsEnabled).toBe(true);
|
|
316
|
+
expect(config.gatesEnabled).toBe(true);
|
|
317
|
+
});
|
|
318
|
+
});
|