@bolloon/bolloon-agent 0.1.35 → 0.1.37
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 +1 -1
- package/dist/agents/p2p-chat-tools.js +6 -6
- package/dist/agents/permission-mode.js +115 -0
- package/dist/agents/pi-sdk.js +435 -25
- package/dist/agents/pre-tool-validator.js +194 -0
- package/dist/agents/workflow-pivot-loop.js +113 -12
- package/dist/bollharness-integration/context-router.js +2 -2
- package/dist/bollharness-integration/guard-checker.js +1 -1
- package/dist/bootstrap/bootstrap.js +3 -0
- package/dist/bootstrap/context-collector.js +17 -1
- package/dist/bootstrap/context-hierarchy.js +218 -0
- package/dist/bootstrap/lifecycle-hooks.js +86 -24
- package/dist/bootstrap/project-context.js +10 -3
- package/dist/context-compaction/auto-compact.js +144 -0
- package/dist/context-compaction/budget-gate.js +28 -0
- package/dist/context-compaction/budget-reduce.js +35 -0
- package/dist/context-compaction/context-collapse.js +66 -0
- package/dist/context-compaction/index.js +21 -0
- package/dist/context-compaction/microcompact.js +51 -0
- package/dist/context-compaction/pipeline.js +123 -0
- package/dist/context-compaction/snip.js +45 -0
- package/dist/context-compaction/token-estimator.js +35 -0
- package/dist/context-compaction/types.js +19 -0
- package/dist/heartbeat/HealthMonitor.js +3 -2
- package/dist/index.js +38 -2
- package/dist/llm/llm-judgment-client.js +32 -30
- package/dist/llm/pi-ai.js +103 -16
- package/dist/llm/system-prompt/health.js +129 -0
- package/dist/llm/system-prompt/registry.js +246 -0
- package/dist/llm/system-prompt/strip-hibsml.js +51 -0
- package/dist/llm/tool-manifest/ask_user_input.js +35 -0
- package/dist/llm/tool-manifest/bash.js +23 -0
- package/dist/llm/tool-manifest/create_file.js +24 -0
- package/dist/llm/tool-manifest/fetch_sports_data.js +26 -0
- package/dist/llm/tool-manifest/image_search.js +24 -0
- package/dist/llm/tool-manifest/index.js +69 -0
- package/dist/llm/tool-manifest/mcp.js +43 -0
- package/dist/llm/tool-manifest/message_compose.js +31 -0
- package/dist/llm/tool-manifest/places.js +83 -0
- package/dist/llm/tool-manifest/present_files.js +21 -0
- package/dist/llm/tool-manifest/recipe.js +40 -0
- package/dist/llm/tool-manifest/recommend_apps.js +23 -0
- package/dist/llm/tool-manifest/str_replace.js +27 -0
- package/dist/llm/tool-manifest/types.js +7 -0
- package/dist/llm/tool-manifest/view.js +24 -0
- package/dist/llm/tool-manifest/weather.js +27 -0
- package/dist/llm/tool-manifest/web.js +51 -0
- package/dist/network/p2p-direct.js +23 -0
- package/dist/network/source-intent-broadcaster.js +203 -0
- package/dist/network/source-intent.js +100 -0
- package/dist/pi-ecosystem-judgment/adaptive-scan.js +48 -0
- package/dist/pi-ecosystem-judgment/injection-gate.js +54 -12
- package/dist/pi-ecosystem-judgment/value-injection.js +8 -2
- package/dist/security/context-router-tool.js +1 -1
- package/dist/security/input-scanner.js +223 -0
- package/dist/web/client.js +3089 -4458
- package/dist/web/index.html +58 -67
- package/dist/web/server.js +299 -117
- package/dist/web/style.css +531 -249
- package/dist/web/ui/message-renderer.js +352 -0
- package/dist/web/ui/step-timeline.js +279 -0
- package/package.json +2 -2
- package/.auto-evolve-calls +0 -1
- package/.last-auto-evolve-baseline +0 -1
- package/Bolloon.md +0 -103
- package/dist/agents/constraint-layer.js.map +0 -1
- package/dist/agents/pi-sdk.js.map +0 -1
- package/dist/agents/workflow-engine.js.map +0 -1
- package/dist/bollharness/src/index.js +0 -5
- package/dist/bollharness/src/scripts/checks/check_adr_plan_numbering.js +0 -6
- package/dist/bollharness/src/scripts/checks/check_api_types.js +0 -45
- package/dist/bollharness/src/scripts/checks/check_artifact_link.js +0 -146
- package/dist/bollharness/src/scripts/checks/check_bridge_deps.js +0 -6
- package/dist/bollharness/src/scripts/checks/check_bugfix_binding.js +0 -6
- package/dist/bollharness/src/scripts/checks/check_bugfix_binding_ci.js +0 -6
- package/dist/bollharness/src/scripts/checks/check_doc_file_references.js +0 -6
- package/dist/bollharness/src/scripts/checks/check_doc_freshness.js +0 -135
- package/dist/bollharness/src/scripts/checks/check_doc_links.js +0 -31
- package/dist/bollharness/src/scripts/checks/check_file_existence_claims.js +0 -6
- package/dist/bollharness/src/scripts/checks/check_fragment_integrity.js +0 -34
- package/dist/bollharness/src/scripts/checks/check_hook_installed.js +0 -63
- package/dist/bollharness/src/scripts/checks/check_issue_closure.js +0 -41
- package/dist/bollharness/src/scripts/checks/check_mcp_parity.js +0 -6
- package/dist/bollharness/src/scripts/checks/check_security.js +0 -48
- package/dist/bollharness/src/scripts/checks/check_skill_parity.js +0 -6
- package/dist/bollharness/src/scripts/checks/check_versions.js +0 -6
- package/dist/bollharness/src/scripts/checks/finding.js +0 -13
- package/dist/bollharness/src/scripts/checks/next_decision_number.js +0 -20
- package/dist/bollharness/src/scripts/checks/regenerate_magic_docs.js +0 -6
- package/dist/bollharness/src/scripts/ci/detect_rebaseline_triggers.js +0 -8
- package/dist/bollharness/src/scripts/ci/scan_subprocess_cfg.js +0 -8
- package/dist/bollharness/src/scripts/ci/scan_verify_artifacts.js +0 -8
- package/dist/bollharness/src/scripts/ci/scan_yaml_schema.js +0 -8
- package/dist/bollharness/src/scripts/context_router.js +0 -67
- package/dist/bollharness/src/scripts/deploy-guard.js +0 -157
- package/dist/bollharness/src/scripts/guard-feedback.js +0 -192
- package/dist/bollharness/src/scripts/guard_router.js +0 -158
- package/dist/bollharness/src/scripts/hooks/_hook_output.js +0 -6
- package/dist/bollharness/src/scripts/hooks/auto-python3.js +0 -6
- package/dist/bollharness/src/scripts/hooks/deploy-progress-on-session-end.js +0 -6
- package/dist/bollharness/src/scripts/hooks/failure-analyzer.js +0 -6
- package/dist/bollharness/src/scripts/hooks/gate-judgment-inject.js +0 -92
- package/dist/bollharness/src/scripts/hooks/gate-transition-judgment.js +0 -63
- package/dist/bollharness/src/scripts/hooks/inbox-ack.js +0 -6
- package/dist/bollharness/src/scripts/hooks/inbox-inject-on-start.js +0 -6
- package/dist/bollharness/src/scripts/hooks/inbox-validate.js +0 -6
- package/dist/bollharness/src/scripts/hooks/inbox-write-ledger.js +0 -6
- package/dist/bollharness/src/scripts/hooks/initializer-agent.js +0 -6
- package/dist/bollharness/src/scripts/hooks/loop-detection.js +0 -73
- package/dist/bollharness/src/scripts/hooks/owner-guard.js +0 -6
- package/dist/bollharness/src/scripts/hooks/precompact.js +0 -6
- package/dist/bollharness/src/scripts/hooks/review-agent-gatekeeper.js +0 -6
- package/dist/bollharness/src/scripts/hooks/risk-tracker.js +0 -108
- package/dist/bollharness/src/scripts/hooks/sanitize-on-read.js +0 -6
- package/dist/bollharness/src/scripts/hooks/session-reflection.js +0 -7
- package/dist/bollharness/src/scripts/hooks/session-start-magic-docs.js +0 -7
- package/dist/bollharness/src/scripts/hooks/session-start-reset-risk.js +0 -7
- package/dist/bollharness/src/scripts/hooks/session-start-toolkit-reminder.js +0 -7
- package/dist/bollharness/src/scripts/hooks/stop-evaluator.js +0 -157
- package/dist/bollharness/src/scripts/hooks/tool-call-counter.js +0 -6
- package/dist/bollharness/src/scripts/hooks/trace-analyzer.js +0 -10
- package/dist/bollharness/src/scripts/install/install-trust-token.js +0 -7
- package/dist/bollharness/src/scripts/install/multi_project_registry.js +0 -9
- package/dist/bollharness/src/scripts/install/phase2_auto.js +0 -21
- package/dist/bollharness/src/scripts/install/pre_commit_installer.js +0 -6
- package/dist/bollharness/src/scripts/install/tier_selector.js +0 -7
- package/dist/bollharness/src/scripts/install/transcript_miner.js +0 -7
- package/dist/bollharness/src/scripts/lib/claim_patterns.js +0 -10
- package/dist/bollharness/src/scripts/lib/sanitize_patterns.js +0 -12
- package/dist/bollharness/src/scripts/sanitize.js +0 -6
- package/dist/bollharness-integration/context-router-judgment.js.map +0 -1
- package/dist/bollharness-integration/context-router.js.map +0 -1
- package/dist/bollharness-integration/gate-state-machine.js.map +0 -1
- package/dist/bollharness-integration/gate-transition-hooks.js.map +0 -1
- package/dist/bollharness-integration/guard-checker.js.map +0 -1
- package/dist/bollharness-integration/index.js.map +0 -1
- package/dist/bollharness-integration/integration.js.map +0 -1
- package/dist/bollharness-integration/llm/pi-ai.d.ts +0 -60
- package/dist/bollharness-integration/pi-ecosystem-colony/index.d.ts +0 -153
- package/dist/bollharness-integration/pi-ecosystem-goals/index.d.ts +0 -136
- package/dist/bollharness-integration/pi-ecosystem-judgment/decision.d.ts +0 -117
- package/dist/bollharness-integration/pi-ecosystem-judgment/distillation.d.ts +0 -78
- package/dist/bollharness-integration/pi-ecosystem-judgment/index.d.ts +0 -139
- package/dist/bollharness-integration/pi-ecosystem-mcp/index.d.ts +0 -127
- package/dist/bollharness-integration/pi-ecosystem-subagents/index.d.ts +0 -95
- package/dist/bollharness-integration/skill-adapter.js.map +0 -1
- package/dist/constraint-runtime/src/_archive_helper.js +0 -9
- package/dist/constraint-runtime/src/agent/coordinator.js +0 -48
- package/dist/constraint-runtime/src/agent/index.js +0 -1
- package/dist/constraint-runtime/src/assistant/index.js +0 -12
- package/dist/constraint-runtime/src/bootstrap/index.js +0 -12
- package/dist/constraint-runtime/src/bootstrap_graph.js +0 -13
- package/dist/constraint-runtime/src/bridge/index.js +0 -12
- package/dist/constraint-runtime/src/buddy/index.js +0 -12
- package/dist/constraint-runtime/src/cli/index.js +0 -12
- package/dist/constraint-runtime/src/command_graph.js +0 -10
- package/dist/constraint-runtime/src/commands.js +0 -60
- package/dist/constraint-runtime/src/components/index.js +0 -12
- package/dist/constraint-runtime/src/constants/index.js +0 -12
- package/dist/constraint-runtime/src/constraint/budget.js +0 -22
- package/dist/constraint-runtime/src/constraint/budget.js.map +0 -1
- package/dist/constraint-runtime/src/constraint/index.js +0 -2
- package/dist/constraint-runtime/src/constraint/permission.js +0 -20
- package/dist/constraint-runtime/src/constraint/permission.js.map +0 -1
- package/dist/constraint-runtime/src/context.js +0 -30
- package/dist/constraint-runtime/src/coordinator/index.js +0 -12
- package/dist/constraint-runtime/src/cost_hook.js +0 -4
- package/dist/constraint-runtime/src/cost_tracker.js +0 -8
- package/dist/constraint-runtime/src/deferred_init.js +0 -10
- package/dist/constraint-runtime/src/direct_modes.js +0 -6
- package/dist/constraint-runtime/src/dynamic-tool-loader.js +0 -85
- package/dist/constraint-runtime/src/entrypoints/index.js +0 -12
- package/dist/constraint-runtime/src/execution_registry.js +0 -44
- package/dist/constraint-runtime/src/history.js +0 -9
- package/dist/constraint-runtime/src/hooks/index.js +0 -12
- package/dist/constraint-runtime/src/index.js +0 -26
- package/dist/constraint-runtime/src/ink.js +0 -4
- package/dist/constraint-runtime/src/keybindings/index.js +0 -12
- package/dist/constraint-runtime/src/memdir/index.js +0 -12
- package/dist/constraint-runtime/src/migrations/index.js +0 -12
- package/dist/constraint-runtime/src/models.js +0 -1
- package/dist/constraint-runtime/src/models.js.map +0 -1
- package/dist/constraint-runtime/src/moreright/index.js +0 -12
- package/dist/constraint-runtime/src/native_ts/index.js +0 -12
- package/dist/constraint-runtime/src/output_styles/index.js +0 -12
- package/dist/constraint-runtime/src/parity_audit.js +0 -12
- package/dist/constraint-runtime/src/plugins/index.js +0 -12
- package/dist/constraint-runtime/src/port_manifest.js +0 -11
- package/dist/constraint-runtime/src/prefetch.js +0 -9
- package/dist/constraint-runtime/src/query.js +0 -1
- package/dist/constraint-runtime/src/remote/index.js +0 -12
- package/dist/constraint-runtime/src/remote_runtime.js +0 -9
- package/dist/constraint-runtime/src/runtime/index.js +0 -1
- package/dist/constraint-runtime/src/runtime/session.js +0 -35
- package/dist/constraint-runtime/src/schemas/index.js +0 -12
- package/dist/constraint-runtime/src/screens/index.js +0 -12
- package/dist/constraint-runtime/src/server/index.js +0 -12
- package/dist/constraint-runtime/src/services/index.js +0 -12
- package/dist/constraint-runtime/src/session_store.js +0 -22
- package/dist/constraint-runtime/src/setup.js +0 -30
- package/dist/constraint-runtime/src/skills/index.js +0 -1
- package/dist/constraint-runtime/src/skills/skill-registry.js +0 -28
- package/dist/constraint-runtime/src/state/index.js +0 -12
- package/dist/constraint-runtime/src/system_init.js +0 -20
- package/dist/constraint-runtime/src/thinking/engine.js +0 -42
- package/dist/constraint-runtime/src/thinking/index.js +0 -1
- package/dist/constraint-runtime/src/tool_pool.js +0 -8
- package/dist/constraint-runtime/src/tools/OpenCLI/execAdapter.js +0 -7
- package/dist/constraint-runtime/src/tools/OpenCLI/listAdapters.js +0 -7
- package/dist/constraint-runtime/src/tools/OpenCLI/runCommand.js +0 -7
- package/dist/constraint-runtime/src/tools/PolymarketSDK/cancelOrder.js +0 -6
- package/dist/constraint-runtime/src/tools/PolymarketSDK/createOrder.js +0 -6
- package/dist/constraint-runtime/src/tools/PolymarketSDK/getMarket.js +0 -5
- package/dist/constraint-runtime/src/tools/PolymarketSDK/getOrders.js +0 -6
- package/dist/constraint-runtime/src/tools/PolymarketSDK/listMarkets.js +0 -4
- package/dist/constraint-runtime/src/tools/SafeSDK/confirmTransaction.js +0 -6
- package/dist/constraint-runtime/src/tools/SafeSDK/createTransaction.js +0 -8
- package/dist/constraint-runtime/src/tools/SafeSDK/deploySafe.js +0 -6
- package/dist/constraint-runtime/src/tools/SafeSDK/executeTransaction.js +0 -6
- package/dist/constraint-runtime/src/tools/SafeSDK/getBalance.js +0 -6
- package/dist/constraint-runtime/src/tools/SafeSDK/getPendingTransactions.js +0 -6
- package/dist/constraint-runtime/src/tools/SafeSDK/proposeTransaction.js +0 -6
- package/dist/constraint-runtime/src/tools/WalletTools/autoPay.js +0 -29
- package/dist/constraint-runtime/src/tools/WalletTools/createWallet.js +0 -10
- package/dist/constraint-runtime/src/tools/WalletTools/getBalance.js +0 -13
- package/dist/constraint-runtime/src/tools/WalletTools/importWallet.js +0 -22
- package/dist/constraint-runtime/src/tools/WalletTools/sendTransaction.js +0 -25
- package/dist/constraint-runtime/src/tools/WalletTools/signMessage.js +0 -10
- package/dist/constraint-runtime/src/tools/WalletTools/transferToken.js +0 -25
- package/dist/constraint-runtime/src/tools.js +0 -80
- package/dist/constraint-runtime/src/transcript.js +0 -19
- package/dist/constraint-runtime/src/types/index.js +0 -12
- package/dist/constraint-runtime/src/upstream_proxy/index.js +0 -12
- package/dist/constraint-runtime/src/utils/index.js +0 -12
- package/dist/constraint-runtime/src/vim/index.js +0 -12
- package/dist/constraint-runtime/src/voice/index.js +0 -12
- package/dist/constraints/index.js.map +0 -1
- package/dist/documents/reader.js.map +0 -1
- package/dist/llm/config-store.js.map +0 -1
- package/dist/llm/pi-ai.js.map +0 -1
- package/dist/network/agent-network.js.map +0 -1
- package/dist/network/iroh-integration.js.map +0 -1
- package/dist/network/iroh-transport.js.map +0 -1
- package/dist/network/p2p.js.map +0 -1
- package/dist/network/storage/adapters/json-adapter.js.map +0 -1
- package/dist/pi-ecosystem-colony/index.js.map +0 -1
- package/dist/pi-ecosystem-goals/index.js.map +0 -1
- package/dist/pi-ecosystem-judgment/decision.js.map +0 -1
- package/dist/pi-ecosystem-judgment/distillation.js.map +0 -1
- package/dist/pi-ecosystem-judgment/human-value-store.js.map +0 -1
- package/dist/pi-ecosystem-judgment/index.js.map +0 -1
- package/dist/pi-ecosystem-judgment/value-injection.js.map +0 -1
- package/dist/pi-ecosystem-mcp/index.js.map +0 -1
- package/dist/pi-ecosystem-subagents/index.js.map +0 -1
- package/dist/social/ant-colony/AdaptiveHeartbeat.js.map +0 -1
- package/dist/social/ant-colony/PheromoneEngine.js.map +0 -1
- package/dist/social/ant-colony/types.js.map +0 -1
- package/dist/social/channels/ChannelManager.js.map +0 -1
- package/dist/social/channels/DiapChannelBridge.js.map +0 -1
- package/dist/social/channels/InterestMatcher.js.map +0 -1
- package/dist/social/channels/types.js.map +0 -1
- package/dist/social/global-shared-context.js.map +0 -1
- package/dist/social/heartbeat.js.map +0 -1
- package/lefthook.yml +0 -29
- package/scripts/auto-evolve-loop.ts +0 -376
- package/scripts/auto-evolve-oneshot.sh +0 -155
- package/scripts/auto-evolve-snapshot.sh +0 -136
- package/scripts/build-cli.js +0 -216
- package/scripts/build-web.ts +0 -82
- package/scripts/detect-schema-changes.sh +0 -48
- package/scripts/diff-reviewer.ts +0 -159
- package/scripts/postinstall.js +0 -153
- package/scripts/weekly-report.ts +0 -364
- package/src/agents/agent-manifest-protocol.ts +0 -117
- package/src/agents/constraint-layer.ts +0 -309
- package/src/agents/iroh-secret.ts +0 -32
- package/src/agents/p2p-chat-tools.ts +0 -383
- package/src/agents/p2p-document-tools.ts +0 -347
- package/src/agents/pi-sdk.ts +0 -2462
- package/src/agents/protocol.ts +0 -398
- package/src/agents/shell-guard.ts +0 -417
- package/src/agents/shell-tool.ts +0 -103
- package/src/agents/skill-loader.ts +0 -202
- package/src/agents/subagent-manager.ts +0 -553
- package/src/agents/workflow-engine.ts +0 -332
- package/src/agents/workflow-pivot-loop.ts +0 -675
- package/src/bollharness/.sanitize-report.json +0 -13
- package/src/bollharness/CLAUDE.md +0 -73
- package/src/bollharness/LICENSE +0 -21
- package/src/bollharness/README.md +0 -143
- package/src/bollharness/README.zh-CN.md +0 -131
- package/src/bollharness/package.json +0 -20
- package/src/bollharness/reference/SOURCE-COMMIT.txt +0 -3
- package/src/bollharness/reference/boll-reference/scripts/hooks/.sanitize-report.json +0 -12
- package/src/bollharness/reference/boll-reference/scripts/hooks/find-boll-root.sh +0 -27
- package/src/bollharness/reference/boll-reference/scripts/hooks/precompact.sh +0 -57
- package/src/bollharness/reference/boll-reference/scripts/hooks/stop-evaluator.md +0 -57
- package/src/bollharness/schemas/metrics-jsonl-allowlist.json +0 -67
- package/src/bollharness/scripts/checks/next_decision_number.sh +0 -48
- package/src/bollharness/scripts/ci/count-components.sh +0 -65
- package/src/bollharness/scripts/context-fragments/artifact-linkage.md +0 -14
- package/src/bollharness/scripts/context-fragments/auth-consumers.md +0 -17
- package/src/bollharness/scripts/context-fragments/bridge-constitution.md +0 -13
- package/src/bollharness/scripts/context-fragments/catalyst-distributed.md +0 -18
- package/src/bollharness/scripts/context-fragments/closure-checklist.md +0 -13
- package/src/bollharness/scripts/context-fragments/contract-consumers.md +0 -15
- package/src/bollharness/scripts/context-fragments/db-shared-structures.md +0 -15
- package/src/bollharness/scripts/context-fragments/fixed-three-layers.md +0 -19
- package/src/bollharness/scripts/context-fragments/general-dev-principles.md +0 -11
- package/src/bollharness/scripts/context-fragments/issue-first.md +0 -8
- package/src/bollharness/scripts/context-fragments/mcp-parity.md +0 -16
- package/src/bollharness/scripts/context-fragments/pi-agent-operations.md +0 -108
- package/src/bollharness/scripts/context-fragments/protocol-consumers.md +0 -15
- package/src/bollharness/scripts/context-fragments/run-events-consumers.md +0 -15
- package/src/bollharness/scripts/context-fragments/scene-fidelity.md +0 -13
- package/src/bollharness/scripts/context-fragments/truth-source-hierarchy.md +0 -15
- package/src/bollharness/scripts/context-fragments/two-language.md +0 -15
- package/src/bollharness/scripts/context-fragments/version-sources.md +0 -14
- package/src/bollharness/scripts/hooks/find-project-root.sh +0 -47
- package/src/bollharness/scripts/hooks/inbox-poll.sh +0 -78
- package/src/bollharness/scripts/hooks/precompact.sh +0 -56
- package/src/bollharness/scripts/hooks/stop-evaluator.md +0 -83
- package/src/bollharness/scripts/sync-from-upstream.sh +0 -281
- package/src/bollharness/src/index.ts +0 -5
- package/src/bollharness/src/scripts/checks/check_adr_plan_numbering.ts +0 -11
- package/src/bollharness/src/scripts/checks/check_api_types.ts +0 -52
- package/src/bollharness/src/scripts/checks/check_artifact_link.ts +0 -156
- package/src/bollharness/src/scripts/checks/check_bridge_deps.ts +0 -11
- package/src/bollharness/src/scripts/checks/check_bugfix_binding.ts +0 -11
- package/src/bollharness/src/scripts/checks/check_bugfix_binding_ci.ts +0 -11
- package/src/bollharness/src/scripts/checks/check_doc_file_references.ts +0 -11
- package/src/bollharness/src/scripts/checks/check_doc_freshness.ts +0 -141
- package/src/bollharness/src/scripts/checks/check_doc_links.ts +0 -36
- package/src/bollharness/src/scripts/checks/check_file_existence_claims.ts +0 -11
- package/src/bollharness/src/scripts/checks/check_fragment_integrity.ts +0 -40
- package/src/bollharness/src/scripts/checks/check_hook_installed.ts +0 -70
- package/src/bollharness/src/scripts/checks/check_issue_closure.ts +0 -51
- package/src/bollharness/src/scripts/checks/check_mcp_parity.ts +0 -11
- package/src/bollharness/src/scripts/checks/check_security.ts +0 -54
- package/src/bollharness/src/scripts/checks/check_skill_parity.ts +0 -11
- package/src/bollharness/src/scripts/checks/check_versions.ts +0 -11
- package/src/bollharness/src/scripts/checks/finding.ts +0 -35
- package/src/bollharness/src/scripts/checks/next_decision_number.ts +0 -24
- package/src/bollharness/src/scripts/checks/regenerate_magic_docs.ts +0 -11
- package/src/bollharness/src/scripts/ci/detect_rebaseline_triggers.ts +0 -14
- package/src/bollharness/src/scripts/ci/scan_subprocess_cfg.ts +0 -14
- package/src/bollharness/src/scripts/ci/scan_verify_artifacts.ts +0 -14
- package/src/bollharness/src/scripts/ci/scan_yaml_schema.ts +0 -14
- package/src/bollharness/src/scripts/context_router.ts +0 -76
- package/src/bollharness/src/scripts/deploy-guard.ts +0 -182
- package/src/bollharness/src/scripts/guard-feedback.ts +0 -215
- package/src/bollharness/src/scripts/guard_router.ts +0 -194
- package/src/bollharness/src/scripts/hooks/_hook_output.js +0 -3
- package/src/bollharness/src/scripts/hooks/_hook_output.ts +0 -11
- package/src/bollharness/src/scripts/hooks/auto-python3.ts +0 -10
- package/src/bollharness/src/scripts/hooks/deploy-progress-on-session-end.ts +0 -10
- package/src/bollharness/src/scripts/hooks/failure-analyzer.ts +0 -10
- package/src/bollharness/src/scripts/hooks/gate-judgment-inject.ts +0 -111
- package/src/bollharness/src/scripts/hooks/gate-transition-judgment.ts +0 -74
- package/src/bollharness/src/scripts/hooks/inbox-ack.ts +0 -10
- package/src/bollharness/src/scripts/hooks/inbox-inject-on-start.ts +0 -10
- package/src/bollharness/src/scripts/hooks/inbox-validate.ts +0 -10
- package/src/bollharness/src/scripts/hooks/inbox-write-ledger.ts +0 -10
- package/src/bollharness/src/scripts/hooks/initializer-agent.ts +0 -10
- package/src/bollharness/src/scripts/hooks/loop-detection.ts +0 -83
- package/src/bollharness/src/scripts/hooks/owner-guard.ts +0 -10
- package/src/bollharness/src/scripts/hooks/precompact.ts +0 -10
- package/src/bollharness/src/scripts/hooks/review-agent-gatekeeper.ts +0 -10
- package/src/bollharness/src/scripts/hooks/risk-tracker.ts +0 -121
- package/src/bollharness/src/scripts/hooks/sanitize-on-read.ts +0 -10
- package/src/bollharness/src/scripts/hooks/session-reflection.ts +0 -12
- package/src/bollharness/src/scripts/hooks/session-start-magic-docs.ts +0 -12
- package/src/bollharness/src/scripts/hooks/session-start-reset-risk.ts +0 -12
- package/src/bollharness/src/scripts/hooks/session-start-toolkit-reminder.ts +0 -12
- package/src/bollharness/src/scripts/hooks/stop-evaluator.ts +0 -164
- package/src/bollharness/src/scripts/hooks/tool-call-counter.ts +0 -10
- package/src/bollharness/src/scripts/hooks/trace-analyzer.ts +0 -14
- package/src/bollharness/src/scripts/install/install-trust-token.ts +0 -13
- package/src/bollharness/src/scripts/install/multi_project_registry.ts +0 -13
- package/src/bollharness/src/scripts/install/phase2_auto.ts +0 -28
- package/src/bollharness/src/scripts/install/pre_commit_installer.ts +0 -10
- package/src/bollharness/src/scripts/install/tier_selector.ts +0 -10
- package/src/bollharness/src/scripts/install/transcript_miner.ts +0 -13
- package/src/bollharness/src/scripts/lib/claim_patterns.ts +0 -11
- package/src/bollharness/src/scripts/lib/sanitize_patterns.ts +0 -13
- package/src/bollharness/src/scripts/sanitize.ts +0 -9
- package/src/bollharness/templates/persona/default.json +0 -19
- package/src/bollharness/templates/scaffold/.gitignore.append +0 -16
- package/src/bollharness/templates/scaffold/CLAUDE.md +0 -89
- package/src/bollharness-integration/channel-judgment-engine.ts +0 -634
- package/src/bollharness-integration/context-chain-router.ts +0 -474
- package/src/bollharness-integration/context-router-judgment.ts +0 -339
- package/src/bollharness-integration/context-router.ts +0 -583
- package/src/bollharness-integration/gate-state-machine.ts +0 -444
- package/src/bollharness-integration/gate-transition-hooks.ts +0 -137
- package/src/bollharness-integration/guard-checker.ts +0 -451
- package/src/bollharness-integration/index.ts +0 -195
- package/src/bollharness-integration/integration.ts +0 -538
- package/src/bollharness-integration/judgment-prompts.yaml +0 -535
- package/src/bollharness-integration/llm-judgment-engine.ts +0 -712
- package/src/bollharness-integration/skill-adapter.ts +0 -646
- package/src/bootstrap/bootstrap.ts +0 -132
- package/src/bootstrap/context-collector.ts +0 -342
- package/src/bootstrap/lifecycle-hooks.ts +0 -176
- package/src/bootstrap/project-context.ts +0 -163
- package/src/cli/interface.ts +0 -211
- package/src/cli-entry.ts +0 -304
- package/src/constraints/index.ts +0 -6
- package/src/documents/reader.ts +0 -85
- package/src/documents/store.ts +0 -252
- package/src/electron-preload.ts +0 -25
- package/src/electron.ts +0 -200
- package/src/heartbeat/DaemonManager.ts +0 -283
- package/src/heartbeat/HealthMonitor.ts +0 -316
- package/src/heartbeat/StartupVerifier.ts +0 -223
- package/src/heartbeat/Watchdog.ts +0 -208
- package/src/heartbeat/index.ts +0 -109
- package/src/heartbeat/self-improve-bus.ts +0 -110
- package/src/heartbeat/types.ts +0 -82
- package/src/index.ts +0 -1690
- package/src/llm/audio-config-store.ts +0 -246
- package/src/llm/config-store.ts +0 -400
- package/src/llm/llm-judgment-client.ts +0 -470
- package/src/llm/pi-ai.ts +0 -558
- package/src/llm/video-config-store.ts +0 -257
- package/src/network/agent-network.ts +0 -800
- package/src/network/hybrid-messenger.ts +0 -199
- package/src/network/iroh-bootstrap.ts +0 -57
- package/src/network/iroh-discovery.ts +0 -208
- package/src/network/iroh-integration.ts +0 -158
- package/src/network/iroh-transport.ts +0 -637
- package/src/network/known-peers.ts +0 -102
- package/src/network/p2p-direct.ts +0 -240
- package/src/network/p2p-secret.ts +0 -153
- package/src/network/p2p.ts +0 -964
- package/src/network/storage/adapters/json-adapter.ts +0 -454
- package/src/network/storage/index.ts +0 -203
- package/src/network/storage/types.ts +0 -166
- package/src/security/builtin-guards.ts +0 -162
- package/src/security/context-router-tool.ts +0 -122
- package/src/security/react-harness.ts +0 -177
- package/src/security/tool-gate.ts +0 -294
- package/src/social/ant-colony/index.js +0 -19
- package/src/social/channels/ChannelManager.ts +0 -485
- package/src/social/channels/DiapChannelBridge.ts +0 -501
- package/src/social/channels/InterestMatcher.ts +0 -189
- package/src/social/channels/agent-workflow-config.json +0 -214
- package/src/social/channels/agent-workflow-config.yaml +0 -334
- package/src/social/channels/channel-agent-session.ts +0 -407
- package/src/social/channels/channel-heartbeat-agent.ts +0 -622
- package/src/social/channels/diap-doc-parser.ts +0 -282
- package/src/social/channels/harness-workflow-integrator.ts +0 -594
- package/src/social/channels/index.ts +0 -22
- package/src/social/channels/types.ts +0 -115
- package/src/social/global-shared-context.ts +0 -506
- package/src/social/heartbeat.ts +0 -1057
- package/src/social/persona/enhanced-persona.ts +0 -359
- package/src/types.d.ts +0 -12
- package/src/utils/auto-evolve-policy.ts +0 -138
- package/src/utils/auto-update.ts +0 -482
- package/src/utils/clamp.ts +0 -5
- package/src/web/agent-delegate-server.ts +0 -148
- package/src/web/api-config.html +0 -520
- package/src/web/client.js +0 -4898
- package/src/web/components/p2p/P2PModal.tsx +0 -416
- package/src/web/components/p2p/index.ts +0 -566
- package/src/web/components/p2p/index.tsx +0 -297
- package/src/web/components/p2p/p2p-connection.ts +0 -338
- package/src/web/components/p2p/p2p-identity.ts +0 -92
- package/src/web/components/p2p/p2p-manager.ts +0 -147
- package/src/web/components/p2p/p2p-messages.ts +0 -219
- package/src/web/components/p2p/p2p-modal.ts +0 -685
- package/src/web/components/p2p/p2p-store-memory.ts +0 -162
- package/src/web/components/p2p/p2p-tools.ts +0 -315
- package/src/web/components/p2p/types.ts +0 -170
- package/src/web/components/wallet-viem.mjs +0 -118
- package/src/web/design.md +0 -99
- package/src/web/icons/apple-touch-icon.png +0 -0
- package/src/web/icons/favicon-16x16.png +0 -0
- package/src/web/icons/favicon-192x192.png +0 -0
- package/src/web/icons/favicon-32x32.png +0 -0
- package/src/web/icons/favicon-48x48.png +0 -0
- package/src/web/icons/favicon-512x512.png +0 -0
- package/src/web/icons/favicon.icns +0 -0
- package/src/web/icons/favicon.ico +0 -0
- package/src/web/icons/icon.png +0 -0
- package/src/web/icons/image.png +0 -0
- package/src/web/index.html +0 -382
- package/src/web/iroh-delegate-transport.ts +0 -139
- package/src/web/manifest.json +0 -21
- package/src/web/server.ts +0 -5571
- package/src/web/style.css +0 -4455
- package/staging/auto-evolve/clean-001/.review-verdict +0 -9
- package/staging/auto-evolve/clean-001/clean-001.patch +0 -14
- package/staging/auto-evolve/e2e-001/.patch-id +0 -1
- package/staging/auto-evolve/e2e-001/.review-verdict +0 -12
- package/staging/auto-evolve/e2e-001/e2e-001.patch +0 -11
- package/staging/auto-evolve/test-bad/.review-verdict +0 -12
- package/staging/auto-evolve/test-bad/test-bad.patch +0 -11
- package/tsconfig.cli.json +0 -16
- package/tsconfig.electron.json +0 -20
- package/tsconfig.json +0 -18
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pre-Tool Validator — 4 步链式校验
|
|
3
|
+
*
|
|
4
|
+
* 严格对齐 Claude Code 论文 PreToolUse 4 步:
|
|
5
|
+
* 1. modeGate(tool, mode) — bypassPermissions → 直接放行(除 shell)
|
|
6
|
+
* 2. blacklistGate(tool, args) — 6 模式黑名单 (recursive rm, force push, dd 等)
|
|
7
|
+
* 3. shellGuardGate(tool, args) — **完整** shell-guard (checkCommand + checkWritePath), 永远生效
|
|
8
|
+
* 4. schemaGate(tool, args) — 第一版 stub: always allow (后续接入 tool-gate.ts)
|
|
9
|
+
*
|
|
10
|
+
* 每步独立 try/catch, 失败 = 跳过该步, 不阻塞 (与现有 lifecycle-hooks 风格一致)
|
|
11
|
+
*
|
|
12
|
+
* 失败静默: 任何 step 异常 → console.warn + 继续下一 step, 不抛错
|
|
13
|
+
*/
|
|
14
|
+
import { isShellTool } from './permission-mode.js';
|
|
15
|
+
import { checkCommand, checkWritePath } from './shell-guard.js';
|
|
16
|
+
const DANGEROUS_PATTERNS = [
|
|
17
|
+
{ re: /\brm\s+(-[a-z]*f[a-z]*\s+)?-[a-z]*r[a-z]*\s+\//, reason: '禁止递归删除根目录' },
|
|
18
|
+
{ re: /\bgit\s+push\s+.*--force\b/, reason: '禁止 force push' },
|
|
19
|
+
{ re: /\brm\s+-rf\s+~\//, reason: '禁止递归删除 home' },
|
|
20
|
+
{ re: /\bdd\s+if=.*\s+of=\/dev\//, reason: '禁止 dd 覆盖块设备' },
|
|
21
|
+
{ re: /\bcurl\s+.*\|\s*(ba)?sh\b/, reason: '禁止 curl|sh 直执行' },
|
|
22
|
+
{ re: />\s*\/dev\/sd[a-z]/, reason: '禁止写裸设备' },
|
|
23
|
+
];
|
|
24
|
+
/**
|
|
25
|
+
* Step 1: modeGate
|
|
26
|
+
* - bypassPermissions + 非 shell → 直接放行 (但保留 shellGuardRetained 标记)
|
|
27
|
+
* - 其他 → 继续
|
|
28
|
+
*/
|
|
29
|
+
function modeGate(tool, mode) {
|
|
30
|
+
try {
|
|
31
|
+
if (mode === 'bypassPermissions' && !isShellTool(tool)) {
|
|
32
|
+
return { allowed: true, mode, rejectedBy: undefined, shellGuardRetained: false };
|
|
33
|
+
}
|
|
34
|
+
return null; // 不在这一步决定
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
console.warn('[pre-tool] modeGate failed (silent):', err);
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Step 2: blacklistGate
|
|
43
|
+
* 6 模式黑名单 (现有 lifecycle-hooks.ts 行为)
|
|
44
|
+
*/
|
|
45
|
+
function blacklistGate(tool, args, mode) {
|
|
46
|
+
try {
|
|
47
|
+
if (!isShellTool(tool))
|
|
48
|
+
return null;
|
|
49
|
+
const cmd = String(args.command || args.cmd || '');
|
|
50
|
+
if (!cmd)
|
|
51
|
+
return null;
|
|
52
|
+
for (const { re, reason } of DANGEROUS_PATTERNS) {
|
|
53
|
+
if (re.test(cmd)) {
|
|
54
|
+
return { allowed: false, reason, rejectedBy: 'blacklist', mode };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
console.warn('[pre-tool] blacklistGate failed (silent):', err);
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Step 3: shellGuardGate
|
|
66
|
+
* 永远跑 (绕过 mode), 是 bolloon 自身的安全底线
|
|
67
|
+
*
|
|
68
|
+
* 接完整 shell-guard.ts (checkCommand + checkWritePath):
|
|
69
|
+
* - checkCommand 走命令白名单 + 参数黑名单 (允许列表默认 git/node/npm/npx/tsx/tsc/vitest 等)
|
|
70
|
+
* - checkWritePath 走路径黑名单 (硬编码: pi-sdk.ts, shell-guard.ts, .env, .git/, .bolloon/, package.json, dist/ 等)
|
|
71
|
+
*
|
|
72
|
+
* 失败静默: 任何异常 → 跳过这步, 不阻塞
|
|
73
|
+
*/
|
|
74
|
+
function shellGuardGate(tool, args, mode) {
|
|
75
|
+
try {
|
|
76
|
+
if (!isShellTool(tool))
|
|
77
|
+
return null;
|
|
78
|
+
// 1. 命令检查 (含白名单 + arg 黑名单)
|
|
79
|
+
const cmd = String(args.command || args.cmd || '');
|
|
80
|
+
let bin = '';
|
|
81
|
+
if (cmd) {
|
|
82
|
+
// shell-guard 期望 (cmd, args[]) 形式
|
|
83
|
+
// 简单 split: 第一个 token 是 cmd, 之后是 args
|
|
84
|
+
const parts = cmd.split(/\s+/).filter(Boolean);
|
|
85
|
+
bin = parts[0] || '';
|
|
86
|
+
const rest = parts.slice(1);
|
|
87
|
+
if (bin) {
|
|
88
|
+
const cmdResult = checkCommand(bin, rest);
|
|
89
|
+
if (!cmdResult.allowed) {
|
|
90
|
+
return {
|
|
91
|
+
allowed: false,
|
|
92
|
+
reason: cmdResult.reason,
|
|
93
|
+
rejectedBy: 'shell-guard',
|
|
94
|
+
mode,
|
|
95
|
+
shellGuardRetained: true,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// 2. 写路径检查 — 从 2 个来源抽:
|
|
101
|
+
// a) 结构化字段 (args.path / args.target / args.file)
|
|
102
|
+
// b) 命令字符串里的 token (老测试传 args.command='cat pi-sdk.ts' 时也能拦)
|
|
103
|
+
const pathCandidates = [];
|
|
104
|
+
const structured = String(args.path || args.target || args.file || args.targetPath || args.destination || '');
|
|
105
|
+
if (structured)
|
|
106
|
+
pathCandidates.push(structured);
|
|
107
|
+
if (cmd) {
|
|
108
|
+
// 简单 tokenize: 按空白切, 取不含 shell 元字符的 token
|
|
109
|
+
const tokens = cmd.split(/\s+/).filter((t) => t && !/^[|>;&`$()<]/.test(t));
|
|
110
|
+
for (const t of tokens) {
|
|
111
|
+
if (t !== bin)
|
|
112
|
+
pathCandidates.push(t); // 跳过命令本身
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// 纯文件名 denylist (兜底 — checkWritePath 的 regex 要求 /src/xxx/ 锚定, 纯文件名拦不到)
|
|
116
|
+
// 只对**写/删/改**类命令生效 (rm, cp, mv, sed -i, echo >); 读类命令 (cat, head, tail, ls) 跳过
|
|
117
|
+
const READ_BINS = new Set(['cat', 'head', 'tail', 'wc', 'ls', 'echo', 'pwd', 'date', 'mkdir', 'touch', 'find', 'grep', 'git', 'node', 'npm', 'npx', 'tsx', 'tsc', 'vitest']);
|
|
118
|
+
const FILENAME_DENYLIST = [
|
|
119
|
+
'pi-sdk.ts', 'shell-guard.ts', 'shell-tool.ts',
|
|
120
|
+
'.env', 'package.json', 'tsconfig.json',
|
|
121
|
+
];
|
|
122
|
+
const isReadOperation = READ_BINS.has(bin);
|
|
123
|
+
for (const candidate of pathCandidates) {
|
|
124
|
+
// 2a. checkWritePath 只对写操作调用 (读类命令绕开, 避免 cat pi-sdk.ts 误拦)
|
|
125
|
+
if (!isReadOperation) {
|
|
126
|
+
const pathResult = checkWritePath(candidate);
|
|
127
|
+
if (!pathResult.allowed) {
|
|
128
|
+
return {
|
|
129
|
+
allowed: false,
|
|
130
|
+
reason: pathResult.reason,
|
|
131
|
+
rejectedBy: 'shell-guard',
|
|
132
|
+
mode,
|
|
133
|
+
shellGuardRetained: true,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// 2b. 纯文件名兜底 — 只对写操作生效
|
|
138
|
+
if (!isReadOperation) {
|
|
139
|
+
const baseName = candidate.split('/').pop() || '';
|
|
140
|
+
if (FILENAME_DENYLIST.includes(baseName)) {
|
|
141
|
+
return {
|
|
142
|
+
allowed: false,
|
|
143
|
+
reason: `shell-guard: 禁止 ${bin} 操作 ${candidate} (命中文件名硬编码黑名单)`,
|
|
144
|
+
rejectedBy: 'shell-guard',
|
|
145
|
+
mode,
|
|
146
|
+
shellGuardRetained: true,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return null; // 通过
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
console.warn('[pre-tool] shellGuardGate failed (silent):', err);
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Step 4: schemaGate
|
|
160
|
+
* 第一版 stub: always allow
|
|
161
|
+
*/
|
|
162
|
+
function schemaGate(_tool, _args, mode) {
|
|
163
|
+
return null; // 不在这一步决定
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* 主入口: 4 步链式, 任何一步拒绝 → 返回, 否则最终放行
|
|
167
|
+
*/
|
|
168
|
+
export function validatePreToolUse(tool, args, mode) {
|
|
169
|
+
const steps = [
|
|
170
|
+
() => modeGate(tool, mode),
|
|
171
|
+
() => blacklistGate(tool, args, mode),
|
|
172
|
+
() => shellGuardGate(tool, args, mode),
|
|
173
|
+
() => schemaGate(tool, args, mode),
|
|
174
|
+
];
|
|
175
|
+
for (const step of steps) {
|
|
176
|
+
const result = step();
|
|
177
|
+
if (result && !result.allowed)
|
|
178
|
+
return result;
|
|
179
|
+
}
|
|
180
|
+
// 全部通过 → 放行
|
|
181
|
+
// bypassPermissions + shell 走到这里 = shellGuardGate 已经放过, 但要标记 shellGuardRetained
|
|
182
|
+
return {
|
|
183
|
+
allowed: true,
|
|
184
|
+
mode,
|
|
185
|
+
rejectedBy: undefined,
|
|
186
|
+
shellGuardRetained: isShellTool(tool),
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
// ============================================================
|
|
190
|
+
// 测试钩子
|
|
191
|
+
// ============================================================
|
|
192
|
+
export function _resetValidatorForTest() {
|
|
193
|
+
// validator 是 pure, 保留 API 一致
|
|
194
|
+
}
|
|
@@ -208,6 +208,19 @@ export class WorkflowPivotLoop {
|
|
|
208
208
|
type: 'error',
|
|
209
209
|
content: `❌ 未知工具: ${toolCall.name}`
|
|
210
210
|
});
|
|
211
|
+
// 2026-06-15: step-timeline — 未知工具也开/关一个 step 节点
|
|
212
|
+
this.emit({
|
|
213
|
+
type: 'step_start',
|
|
214
|
+
content: `未知工具 ${toolCall.name}`,
|
|
215
|
+
tool: toolCall.name,
|
|
216
|
+
args: toolCall.args || {},
|
|
217
|
+
});
|
|
218
|
+
this.emit({
|
|
219
|
+
type: 'step_error',
|
|
220
|
+
content: `未知工具 ${toolCall.name}`,
|
|
221
|
+
tool: toolCall.name,
|
|
222
|
+
error: 'Unknown tool',
|
|
223
|
+
});
|
|
211
224
|
this.messageHistory.push({
|
|
212
225
|
role: 'tool',
|
|
213
226
|
content: JSON.stringify({ success: false, error: `Unknown tool: ${toolCall.name}` })
|
|
@@ -219,8 +232,26 @@ export class WorkflowPivotLoop {
|
|
|
219
232
|
content: `🔧 执行: ${toolCall.name}`,
|
|
220
233
|
tool: toolCall.name
|
|
221
234
|
});
|
|
235
|
+
// 2026-06-15: step-timeline — 开节点
|
|
236
|
+
this.emit({
|
|
237
|
+
type: 'step_start',
|
|
238
|
+
content: `调用 ${toolCall.name}`,
|
|
239
|
+
tool: toolCall.name,
|
|
240
|
+
args: toolCall.args || {},
|
|
241
|
+
});
|
|
222
242
|
try {
|
|
223
243
|
const result = await tool.execute(toolCall.args ?? {});
|
|
244
|
+
// 2026-06-15: step-timeline — 关闭节点 (success / error)
|
|
245
|
+
this.emit({
|
|
246
|
+
type: result.success ? 'step_done' : 'step_error',
|
|
247
|
+
content: result.success
|
|
248
|
+
? `${toolCall.name} 成功`
|
|
249
|
+
: `${toolCall.name} 失败: ${result.error}`,
|
|
250
|
+
tool: toolCall.name,
|
|
251
|
+
success: result.success,
|
|
252
|
+
output: result.output,
|
|
253
|
+
error: result.error,
|
|
254
|
+
});
|
|
224
255
|
this.emit({
|
|
225
256
|
type: result.success ? 'status' : 'error',
|
|
226
257
|
content: result.success
|
|
@@ -305,9 +336,49 @@ export class WorkflowPivotLoop {
|
|
|
305
336
|
*/
|
|
306
337
|
extractPendingToolUses(content) {
|
|
307
338
|
const pending = [];
|
|
339
|
+
// Pattern 0: <tool_use>{...JSON...}</tool_use> (Anthropic 风格 + minimax 也用)
|
|
340
|
+
// 这次 LLM 输出: <tool_use>\n{"name": "read_document", "arguments": {"path": "/Users/.../README.md"}}\n</tool_use>
|
|
341
|
+
const toolUseRe = /<tool_use>\s*(\{[\s\S]*?\})\s*<\/tool_use>/g;
|
|
342
|
+
let match;
|
|
343
|
+
while ((match = toolUseRe.exec(content)) !== null) {
|
|
344
|
+
try {
|
|
345
|
+
const obj = JSON.parse(match[1]);
|
|
346
|
+
if (obj && obj.name && this.tools.has(obj.name)) {
|
|
347
|
+
const args = this.normalizeArgs(obj.arguments || {});
|
|
348
|
+
pending.push({ name: obj.name, args, description: '', parameters: {} });
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
catch (e) {
|
|
352
|
+
// JSON 解析失败, 继续下一 match
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
// Pattern 0b: <function_calls><invoke name="X"><parameter name="k">v</parameter>...</invoke></function_calls>
|
|
356
|
+
// 这次 minimax LLM 用这种 Anthropic 风格 XML
|
|
357
|
+
const fnCallsRe = /<function_calls>([\s\S]*?)<\/function_calls>/g;
|
|
358
|
+
while ((match = fnCallsRe.exec(content)) !== null) {
|
|
359
|
+
const block = match[1];
|
|
360
|
+
// 抓 <invoke name="X">...</invoke>
|
|
361
|
+
const invokeRe = /<invoke\s+name="(\w+)"\s*>([\s\S]*?)<\/invoke>/g;
|
|
362
|
+
let im;
|
|
363
|
+
while ((im = invokeRe.exec(block)) !== null) {
|
|
364
|
+
const name = im[1];
|
|
365
|
+
if (!this.tools.has(name))
|
|
366
|
+
continue;
|
|
367
|
+
// 抓 <parameter name="k">v</parameter> 列表
|
|
368
|
+
const args = {};
|
|
369
|
+
const paramRe = /<parameter\s+name="(\w+)"\s*>([\s\S]*?)<\/parameter>/g;
|
|
370
|
+
let pm;
|
|
371
|
+
while ((pm = paramRe.exec(im[2])) !== null) {
|
|
372
|
+
args[pm[1]] = pm[2].trim().replace(/^["']|['"]$/g, '');
|
|
373
|
+
}
|
|
374
|
+
// 避免重复添加
|
|
375
|
+
if (!pending.some(p => p.name === name)) {
|
|
376
|
+
pending.push({ name, args, description: '', parameters: {} });
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
308
380
|
// Pattern 1: Chinese format "调用工具: tool_name(args)"
|
|
309
381
|
const pattern1 = /调用工具[::]\s*(\w+)\s*\(([^)]*)\)/g;
|
|
310
|
-
let match;
|
|
311
382
|
while ((match = pattern1.exec(content)) !== null) {
|
|
312
383
|
const name = match[1];
|
|
313
384
|
const argsStr = match[2];
|
|
@@ -357,22 +428,52 @@ export class WorkflowPivotLoop {
|
|
|
357
428
|
return args;
|
|
358
429
|
const pairs = argsStr.split(',').map(s => s.trim()).filter(Boolean);
|
|
359
430
|
for (const pair of pairs) {
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
431
|
+
// 2026-06-15: LLM 实际输出 3 种格式 — 全支持
|
|
432
|
+
// 1) JSON 风格: {"key":"value"} (服务器日志显示, 但 LLM 不会真输出完整 JSON)
|
|
433
|
+
// 2) key="value" 含双引号 (本次 read_document(path="/Users/..."))
|
|
434
|
+
// 3) key='value' 含单引号
|
|
435
|
+
// 4) key:value (老 Chinese 格式)
|
|
436
|
+
// 5) key value (positional 兜底)
|
|
437
|
+
let m = pair.match(/^["']?([\w-]+)["']?\s*=\s*["']([^"']*)["']$/);
|
|
438
|
+
if (m) {
|
|
439
|
+
args[m[1]] = m[2];
|
|
440
|
+
continue;
|
|
365
441
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
442
|
+
m = pair.match(/^["']?([\w-]+)["']?\s*[:=]\s*([^,]+)$/);
|
|
443
|
+
if (m) {
|
|
444
|
+
args[m[1]] = m[2].trim().replace(/^['"]|['"]$/g, '');
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
447
|
+
m = pair.match(/^["']?([\w-]+)["']?\s*[:]\s*["']?([^"']*)["']?$/);
|
|
448
|
+
if (m) {
|
|
449
|
+
args[m[1]] = m[2].trim();
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
452
|
+
// positional 兜底
|
|
453
|
+
const parts = pair.split(/\s+/);
|
|
454
|
+
if (parts.length >= 2) {
|
|
455
|
+
args[parts[0]] = parts.slice(1).join(' ');
|
|
372
456
|
}
|
|
373
457
|
}
|
|
374
458
|
return args;
|
|
375
459
|
}
|
|
460
|
+
/**
|
|
461
|
+
* 把 tool_use JSON 里的 arguments (已经是对象) 转成 Record<string, string>
|
|
462
|
+
* JSON parser 直接给对象, 但 tool.execute 期望 Record<string, string>
|
|
463
|
+
* 非字符串值 JSON.stringify 一下
|
|
464
|
+
*/
|
|
465
|
+
normalizeArgs(args) {
|
|
466
|
+
const out = {};
|
|
467
|
+
for (const [k, v] of Object.entries(args || {})) {
|
|
468
|
+
if (v == null)
|
|
469
|
+
continue;
|
|
470
|
+
if (typeof v === 'string')
|
|
471
|
+
out[k] = v;
|
|
472
|
+
else
|
|
473
|
+
out[k] = JSON.stringify(v);
|
|
474
|
+
}
|
|
475
|
+
return out;
|
|
476
|
+
}
|
|
376
477
|
/**
|
|
377
478
|
* Build context from message history
|
|
378
479
|
*/
|
|
@@ -25,7 +25,7 @@ export const CONTEXT_MAP = {
|
|
|
25
25
|
'src/bollharness-integration/': ['truth-source-hierarchy', 'artifact-linkage'],
|
|
26
26
|
'docs/': ['truth-source-hierarchy', 'two-language'],
|
|
27
27
|
'docs/decisions/': ['truth-source-hierarchy', 'artifact-linkage'],
|
|
28
|
-
'
|
|
28
|
+
'Bolloon.md': ['truth-source-hierarchy', 'bridge-constitution'],
|
|
29
29
|
'README.md': ['truth-source-hierarchy', 'general-dev-principles'],
|
|
30
30
|
};
|
|
31
31
|
/**
|
|
@@ -331,7 +331,7 @@ export const CONTEXT_FRAGMENTS = {
|
|
|
331
331
|
'project-governance': `# Project Governance
|
|
332
332
|
|
|
333
333
|
## Truth Sources
|
|
334
|
-
-
|
|
334
|
+
- Bolloon.md: Project overview and norms
|
|
335
335
|
- docs/: Architecture and decisions
|
|
336
336
|
- code/: Implementation
|
|
337
337
|
- issues/: Tracking and discussions
|
|
@@ -36,7 +36,7 @@ export const GUARD_MAP = {
|
|
|
36
36
|
'src/constraints/': ['check_api_types', 'check_versions'],
|
|
37
37
|
'src/social/': ['check_api_types', 'check_versions'],
|
|
38
38
|
'docs/': ['check_doc_freshness', 'check_doc_links'],
|
|
39
|
-
'
|
|
39
|
+
'Bolloon.md': ['check_doc_freshness', 'check_artifact_link'],
|
|
40
40
|
'README.md': ['check_doc_freshness'],
|
|
41
41
|
'docs/decisions/': ['check_artifact_link', 'check_versions'],
|
|
42
42
|
'.boll/': ['check_hook_installed'],
|
|
@@ -25,6 +25,7 @@ export async function bootstrapBolloon(opts = {}) {
|
|
|
25
25
|
};
|
|
26
26
|
try {
|
|
27
27
|
scanResult = await runAdaptiveScan();
|
|
28
|
+
const { suggestionHint } = await import('../pi-ecosystem-judgment/adaptive-scan.js');
|
|
28
29
|
await logEvolution({
|
|
29
30
|
ts: new Date().toISOString(),
|
|
30
31
|
action: 'accept', // 用 accept 表示"系统记录" (跟 reject 区分)
|
|
@@ -35,6 +36,7 @@ export async function bootstrapBolloon(opts = {}) {
|
|
|
35
36
|
decision: 'Bolloon 启动扫描',
|
|
36
37
|
reason: `本次启动扫描了 ${scanResult.judgmentsTotal} 条原则, ${scanResult.usageEntriesScanned} 条使用记录, 生成 ${scanResult.suggestions.length} 条建议`,
|
|
37
38
|
action: 'review',
|
|
39
|
+
hint: suggestionHint('unused', 'review', { usage7d: 0, usage30d: 0, daysSinceLastUse: 0, totalUsage: 0 }),
|
|
38
40
|
metrics: { usage7d: 0, usage30d: 0, daysSinceLastUse: 0, totalUsage: 0 },
|
|
39
41
|
scannedAt: scanResult.scannedAt,
|
|
40
42
|
},
|
|
@@ -50,6 +52,7 @@ export async function bootstrapBolloon(opts = {}) {
|
|
|
50
52
|
projectRoot: opts.cwd ?? process.cwd(),
|
|
51
53
|
projectName: 'unknown',
|
|
52
54
|
bolloonMd: null,
|
|
55
|
+
hierarchy: { managed: null, user: null, project: null, local: null, merged: '' },
|
|
53
56
|
git: null,
|
|
54
57
|
persona: null,
|
|
55
58
|
judgmentsSummary: { total: 0, active: 0, superseded: 0, rejected: 0, topValues: [] },
|
|
@@ -57,6 +57,20 @@ async function collectProject(cwd, bolloonMdMaxBytes) {
|
|
|
57
57
|
const bolloonMd = await safeReadFile(path.join(cwd, 'Bolloon.md'), bolloonMdMaxBytes);
|
|
58
58
|
return { projectName, bolloonMd };
|
|
59
59
|
}
|
|
60
|
+
async function collectHierarchy(cwd) {
|
|
61
|
+
// 动态 import 避免循环依赖
|
|
62
|
+
const { collectHierarchyLayers, mergeHierarchyLayers } = await import('./context-hierarchy.js');
|
|
63
|
+
try {
|
|
64
|
+
const layers = await collectHierarchyLayers({ cwd });
|
|
65
|
+
const merged = mergeHierarchyLayers(layers, { maxChars: DEFAULT_HIERARCHY_MERGED_MAX });
|
|
66
|
+
return { ...layers, merged };
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
console.warn('[context-collector] collectHierarchy failed (silent):', err);
|
|
70
|
+
return { managed: null, user: null, project: null, local: null, merged: '' };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const DEFAULT_HIERARCHY_MERGED_MAX = 2000; // 4000 → 2000 (P-Action 4), 跟 context-hierarchy.ts DEFAULT_MERGE_MAX_CHARS 对齐
|
|
60
74
|
async function collectGit(cwd, limit) {
|
|
61
75
|
const branchOut = await safeExecFile('git', ['rev-parse', '--abbrev-ref', 'HEAD'], cwd);
|
|
62
76
|
if (!branchOut)
|
|
@@ -255,13 +269,14 @@ async function walkDir(dir, cb) {
|
|
|
255
269
|
export async function collectBolloonContext(opts) {
|
|
256
270
|
const { cwd, bolloonMdMaxBytes = 2000, gitCommitLimit = 5, topValuesLimit = 10, } = opts;
|
|
257
271
|
// 并行收集 (除 judgments 因为要动态 import + 依赖其它)
|
|
258
|
-
const [project, git, persona, skills, env, pending] = await Promise.all([
|
|
272
|
+
const [project, git, persona, skills, env, pending, hierarchy] = await Promise.all([
|
|
259
273
|
collectProject(cwd, bolloonMdMaxBytes),
|
|
260
274
|
collectGit(cwd, gitCommitLimit),
|
|
261
275
|
collectPersona(),
|
|
262
276
|
collectSkills(),
|
|
263
277
|
Promise.resolve(collectEnv()),
|
|
264
278
|
collectPending(opts),
|
|
279
|
+
collectHierarchy(cwd),
|
|
265
280
|
]);
|
|
266
281
|
// judgments 单独调 (内部 import)
|
|
267
282
|
const judgmentsSummary = await collectJudgmentsSummary(topValuesLimit);
|
|
@@ -269,6 +284,7 @@ export async function collectBolloonContext(opts) {
|
|
|
269
284
|
projectRoot: cwd,
|
|
270
285
|
projectName: project.projectName,
|
|
271
286
|
bolloonMd: project.bolloonMd,
|
|
287
|
+
hierarchy,
|
|
272
288
|
git,
|
|
273
289
|
persona,
|
|
274
290
|
judgmentsSummary,
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context Hierarchy — 4 级 Bolloon.md 查找 + 合并优先级
|
|
3
|
+
*
|
|
4
|
+
* 设计: 严格对齐 Claude Code 论文 4 级层次
|
|
5
|
+
* 1. Managed — /etc/bolloon/Bolloon.md (企业 IT 部署, 系统级)
|
|
6
|
+
* 2. User — ~/.bolloon/Bolloon.md (用户级, 跨项目)
|
|
7
|
+
* 3. Project — <cwd>/Bolloon.md 或 .claude/rules/*.md
|
|
8
|
+
* 4. Local — <cwd>/CLAUDE.local.md (个人覆盖, .gitignore)
|
|
9
|
+
*
|
|
10
|
+
* 注入约定 (论文):
|
|
11
|
+
* - 拼到 system prompt 顶部 (作为 user context, 概率性遵守)
|
|
12
|
+
* - 不混入 user 消息 (避免 prompt injection)
|
|
13
|
+
* - 截断时反向砍 local → project → user → managed (优先保 managed, 因为是 bolloon 自身约束)
|
|
14
|
+
*
|
|
15
|
+
* 兼容:
|
|
16
|
+
* - 同时识别 Bolloon.md 和 Bolloon.md (论文用前者, bolloon 历史用后者)
|
|
17
|
+
* - 文件名按优先级: Bolloon.md > Bolloon.md
|
|
18
|
+
*
|
|
19
|
+
* 失败静默: 任何 IO 错误 → 返回 null, 不阻塞主流程.
|
|
20
|
+
*/
|
|
21
|
+
import * as fs from 'fs/promises';
|
|
22
|
+
import * as os from 'os';
|
|
23
|
+
import * as path from 'path';
|
|
24
|
+
export const DEFAULT_PATHS = {
|
|
25
|
+
managed: '/etc/bolloon/Bolloon.md',
|
|
26
|
+
user: '', // 用 resolveUserPath 填
|
|
27
|
+
project: '', // 用 resolveProjectPaths 填
|
|
28
|
+
projectRulesDir: '',
|
|
29
|
+
local: '',
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* 单层字符上限 (P-Action 4 收紧, 阶段 0 把 4 级层次控制在 ≤ 2KB).
|
|
33
|
+
* 反向截断策略保证 managed 优先, 单层超限由 truncate() 截断.
|
|
34
|
+
*/
|
|
35
|
+
export const DEFAULT_MAX_CHARS = {
|
|
36
|
+
managed: 700, // 1500 → 700, 保 bolloon 自身约束
|
|
37
|
+
user: 500, // 1500 → 500, 跨项目偏好
|
|
38
|
+
project: 500, // 2500 → 500, 项目规则
|
|
39
|
+
local: 300, // 1500 → 300, 个人覆盖
|
|
40
|
+
};
|
|
41
|
+
// ============================================================
|
|
42
|
+
// 路径解析
|
|
43
|
+
// ============================================================
|
|
44
|
+
export function resolveUserPath(home) {
|
|
45
|
+
const h = home ?? process.env.HOME ?? os.homedir() ?? '/tmp';
|
|
46
|
+
return path.join(h, '.bolloon', 'Bolloon.md');
|
|
47
|
+
}
|
|
48
|
+
export function resolveProjectPaths(cwd) {
|
|
49
|
+
return {
|
|
50
|
+
project: path.join(cwd, 'Bolloon.md'),
|
|
51
|
+
projectRulesDir: path.join(cwd, '.claude', 'rules'),
|
|
52
|
+
local: path.join(cwd, 'CLAUDE.local.md'),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
// ============================================================
|
|
56
|
+
// 单层读取 (优先 Bolloon.md, fallback Bolloon.md)
|
|
57
|
+
// ============================================================
|
|
58
|
+
/**
|
|
59
|
+
* 读 1 个文件路径, 失败/缺失返回 null.
|
|
60
|
+
* 字符上限由调用方截断 (这里只负责读全文).
|
|
61
|
+
*/
|
|
62
|
+
async function readRuleFile(filePath) {
|
|
63
|
+
try {
|
|
64
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
65
|
+
return content.length > 0 ? content : null;
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* 读 project 层: 优先 Bolloon.md, fallback Bolloon.md, 最后尝试 .claude/rules/*.md
|
|
73
|
+
*/
|
|
74
|
+
async function readProjectLayer(projectPath, projectRulesDir, maxChars) {
|
|
75
|
+
// 1. Bolloon.md
|
|
76
|
+
let content = await readRuleFile(projectPath);
|
|
77
|
+
if (content)
|
|
78
|
+
return truncate(content, maxChars);
|
|
79
|
+
// 2. Bolloon.md (向后兼容)
|
|
80
|
+
const bolloonMdPath = path.join(path.dirname(projectPath), 'Bolloon.md');
|
|
81
|
+
content = await readRuleFile(bolloonMdPath);
|
|
82
|
+
if (content)
|
|
83
|
+
return truncate(content, maxChars);
|
|
84
|
+
// 3. .claude/rules/*.md (合并所有)
|
|
85
|
+
try {
|
|
86
|
+
const entries = await fs.readdir(projectRulesDir, { withFileTypes: true });
|
|
87
|
+
const ruleFiles = entries
|
|
88
|
+
.filter((e) => e.isFile() && e.name.endsWith('.md'))
|
|
89
|
+
.map((e) => path.join(projectRulesDir, e.name))
|
|
90
|
+
.sort();
|
|
91
|
+
if (ruleFiles.length > 0) {
|
|
92
|
+
const parts = [];
|
|
93
|
+
let total = 0;
|
|
94
|
+
for (const f of ruleFiles) {
|
|
95
|
+
const c = await readRuleFile(f);
|
|
96
|
+
if (c) {
|
|
97
|
+
parts.push(`### ${path.basename(f, '.md')}\n${c}`);
|
|
98
|
+
total += c.length;
|
|
99
|
+
if (total >= maxChars)
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (parts.length > 0)
|
|
104
|
+
return truncate(parts.join('\n\n'), maxChars);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch { /* dir 不存在 */ }
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* 并行读 4 层, 任何一层失败 = null (不阻塞其他).
|
|
112
|
+
*/
|
|
113
|
+
export async function collectHierarchyLayers(opts) {
|
|
114
|
+
const limits = { ...DEFAULT_MAX_CHARS, ...(opts.limits?.maxChars ?? {}) };
|
|
115
|
+
const home = opts.home ?? process.env.HOME ?? os.homedir() ?? '/tmp';
|
|
116
|
+
const managedPath = opts.limits?.paths?.managed ?? DEFAULT_PATHS.managed;
|
|
117
|
+
const userPath = opts.limits?.paths?.user ?? resolveUserPath(home);
|
|
118
|
+
const projectPath = opts.limits?.paths?.project ?? path.join(opts.cwd, 'Bolloon.md');
|
|
119
|
+
const projectRulesDir = opts.limits?.paths?.projectRulesDir ?? path.join(opts.cwd, '.claude', 'rules');
|
|
120
|
+
const localPath = opts.limits?.paths?.local ?? path.join(opts.cwd, 'CLAUDE.local.md');
|
|
121
|
+
const [managed, user, project, local] = await Promise.all([
|
|
122
|
+
readRuleFile(managedPath).then((c) => c ? truncate(c, limits.managed) : null),
|
|
123
|
+
readRuleFile(userPath).then((c) => c ? truncate(c, limits.user) : null),
|
|
124
|
+
readProjectLayer(projectPath, projectRulesDir, limits.project),
|
|
125
|
+
readRuleFile(localPath).then((c) => c ? truncate(c, limits.local) : null),
|
|
126
|
+
]);
|
|
127
|
+
return { managed, user, project, local };
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* 4 级合并总字符上限 (P-Action 4 收紧, ≤ 2KB ≈ 500 tokens).
|
|
131
|
+
* 反向截断 (local → project → user → managed) 保证 managed 不丢.
|
|
132
|
+
*/
|
|
133
|
+
export const DEFAULT_MERGE_MAX_CHARS = 2000;
|
|
134
|
+
/**
|
|
135
|
+
* 按 4 级顺序 (managed → user → project → local) 拼接为 markdown 片段.
|
|
136
|
+
*
|
|
137
|
+
* 截断策略: 反向砍 (local → project → user → managed), 优先保 managed.
|
|
138
|
+
* - 总长 < maxChars: 不截断
|
|
139
|
+
* - 总长 ≥ maxChars: 按 (local, project, user) 顺序逐步砍到 firstParagraphs=1
|
|
140
|
+
* - 最后只保 managed (bolloon 自身约束不能丢)
|
|
141
|
+
*/
|
|
142
|
+
export function mergeHierarchyLayers(layers, opts = {}) {
|
|
143
|
+
const maxChars = opts.maxChars ?? DEFAULT_MERGE_MAX_CHARS;
|
|
144
|
+
const parts = [];
|
|
145
|
+
const labels = [
|
|
146
|
+
['managed', '管理规则 (Managed)'],
|
|
147
|
+
['user', '用户规则 (User)'],
|
|
148
|
+
['project', '项目规则 (Project)'],
|
|
149
|
+
['local', '本地规则 (Local)'],
|
|
150
|
+
];
|
|
151
|
+
for (const [key, label] of labels) {
|
|
152
|
+
const content = layers[key];
|
|
153
|
+
if (content) {
|
|
154
|
+
parts.push(`## ${label}\n\n${content}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (parts.length === 0)
|
|
158
|
+
return '';
|
|
159
|
+
let result = parts.join('\n\n---\n\n');
|
|
160
|
+
if (result.length <= maxChars)
|
|
161
|
+
return result;
|
|
162
|
+
// 超限: 反向砍 (local → project → user), 二级回退到 firstParagraphs=1
|
|
163
|
+
return truncateMerged(layers, maxChars);
|
|
164
|
+
}
|
|
165
|
+
function truncateMerged(layers, maxChars) {
|
|
166
|
+
const order = [
|
|
167
|
+
['local', '本地规则 (Local)'],
|
|
168
|
+
['project', '项目规则 (Project)'],
|
|
169
|
+
['user', '用户规则 (User)'],
|
|
170
|
+
['managed', '管理规则 (Managed)'],
|
|
171
|
+
];
|
|
172
|
+
const capped = { ...layers };
|
|
173
|
+
// 反复压缩, 直到总长 ≤ maxChars
|
|
174
|
+
let depth = 0; // 0=原始, 1=firstParagraphs=1, 2=砍半
|
|
175
|
+
while (depth < 3) {
|
|
176
|
+
const parts = [];
|
|
177
|
+
for (const [key, label] of order) {
|
|
178
|
+
const c = capped[key];
|
|
179
|
+
if (!c)
|
|
180
|
+
continue;
|
|
181
|
+
let text = c;
|
|
182
|
+
if (depth === 1)
|
|
183
|
+
text = firstParagraphs(c, 1);
|
|
184
|
+
if (depth === 2)
|
|
185
|
+
text = firstParagraphs(c, 1, Math.floor(maxChars / 4));
|
|
186
|
+
parts.push(`## ${label}\n\n${text}`);
|
|
187
|
+
}
|
|
188
|
+
const joined = parts.reverse().join('\n\n---\n\n'); // 恢复 managed → user → project → local
|
|
189
|
+
if (joined.length <= maxChars)
|
|
190
|
+
return joined;
|
|
191
|
+
depth++;
|
|
192
|
+
}
|
|
193
|
+
// 最后保 managed 一行
|
|
194
|
+
return `## 管理规则 (Managed)\n\n${firstParagraphs(layers.managed ?? '(无)', 1, maxChars - 50)}`;
|
|
195
|
+
}
|
|
196
|
+
// ============================================================
|
|
197
|
+
// 工具
|
|
198
|
+
// ============================================================
|
|
199
|
+
function truncate(s, maxChars) {
|
|
200
|
+
if (s.length <= maxChars)
|
|
201
|
+
return s;
|
|
202
|
+
return s.substring(0, maxChars) + '\n... (truncated)';
|
|
203
|
+
}
|
|
204
|
+
function firstParagraphs(text, count, maxLen) {
|
|
205
|
+
const paragraphs = text.split(/\n\s*\n/).filter((p) => p.trim().length > 0);
|
|
206
|
+
let result = paragraphs.slice(0, count).join('\n\n');
|
|
207
|
+
if (maxLen && result.length > maxLen) {
|
|
208
|
+
result = result.substring(0, maxLen) + '...';
|
|
209
|
+
}
|
|
210
|
+
return result;
|
|
211
|
+
}
|
|
212
|
+
// ============================================================
|
|
213
|
+
// 测试钩子
|
|
214
|
+
// ============================================================
|
|
215
|
+
/** 重置模块级状态 (供测试). 当前无状态, 保留为占位. */
|
|
216
|
+
export function _resetHierarchyForTest() {
|
|
217
|
+
// no-op (collect 是纯函数, 但保留 API 一致)
|
|
218
|
+
}
|