minimal-agent 0.10.0 → 0.12.0
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 +11 -3
- package/package.json +52 -5
- package/plugins/computer_use/.claude-plugin/plugin.json +6 -0
- package/plugins/computer_use/README.md +94 -0
- package/plugins/computer_use/app/_template.md +142 -0
- package/plugins/computer_use/app/chrome.md +165 -0
- package/plugins/computer_use/app/finder.md +76 -0
- package/plugins/computer_use/app/macos-system-settings.md +81 -0
- package/plugins/computer_use/app/microsoft-excel.md +80 -0
- package/plugins/computer_use/app/microsoft-powerpoint.md +80 -0
- package/plugins/computer_use/app/microsoft-word.md +79 -0
- package/plugins/computer_use/app/wechat.md +413 -0
- package/plugins/computer_use/app/weread.md +319 -0
- package/plugins/computer_use/commands/computeruse.md +25 -0
- package/plugins/computer_use/commands/cu.md +9 -0
- package/plugins/computer_use/plugin.js +26 -0
- package/plugins/computer_use/plugin.ts +30 -0
- package/plugins/computer_use/src/capture.js +90 -0
- package/plugins/computer_use/src/capture.ts +104 -0
- package/plugins/computer_use/src/commands.js +91 -0
- package/plugins/computer_use/src/commands.ts +103 -0
- package/plugins/computer_use/src/daemon.js +134 -0
- package/plugins/computer_use/src/daemon.ts +161 -0
- package/plugins/computer_use/src/manuals.js +135 -0
- package/plugins/computer_use/src/manuals.ts +159 -0
- package/plugins/computer_use/src/verify.js +168 -0
- package/plugins/computer_use/src/verify.ts +219 -0
- package/plugins/computer_use/test/commands.test.ts +73 -0
- package/plugins/cron-runner/plugin.ts +38 -0
- package/plugins/cron-runner/src/commands.ts +373 -0
- package/plugins/cron-runner/src/cronTime.ts +155 -0
- package/plugins/cron-runner/src/lock.ts +79 -0
- package/plugins/cron-runner/src/runs.ts +99 -0
- package/plugins/cron-runner/src/scheduleEngine.ts +76 -0
- package/plugins/cron-runner/src/scheduler.ts +376 -0
- package/plugins/cron-runner/src/schema.ts +139 -0
- package/plugins/cron-runner/src/service.ts +193 -0
- package/plugins/cron-runner/src/store.ts +333 -0
- package/plugins/cron-runner/src/types.ts +141 -0
- package/plugins/cron-runner/test/cronTime.test.ts +41 -0
- package/plugins/cron-runner/test/plugin-integration.test.ts +47 -0
- package/plugins/cron-runner/test/scheduleEngine.test.ts +41 -0
- package/plugins/cron-runner/test/service.test.ts +76 -0
- package/plugins/cron-runner/test/store-and-scheduler.test.ts +501 -0
- package/plugins/workflow-runner/plugin.js +56 -2
- package/plugins/workflow-runner/plugin.ts +113 -0
- package/plugins/workflow-runner/src/agentCommon.js +43 -4
- package/plugins/workflow-runner/src/agentCommon.ts +435 -0
- package/plugins/workflow-runner/src/controlFlow/branch.js +40 -0
- package/plugins/workflow-runner/src/controlFlow/branch.ts +46 -0
- package/plugins/workflow-runner/src/controlFlow/loop.js +211 -0
- package/plugins/workflow-runner/src/controlFlow/loop.ts +248 -0
- package/plugins/workflow-runner/src/controlFlow/pause.js +129 -0
- package/plugins/workflow-runner/src/controlFlow/pause.ts +141 -0
- package/plugins/workflow-runner/src/controlFlow/signal.js +21 -0
- package/plugins/workflow-runner/src/controlFlow/signal.ts +29 -0
- package/plugins/workflow-runner/src/controlFlow/types.js +18 -0
- package/plugins/workflow-runner/src/controlFlow/types.ts +63 -0
- package/plugins/workflow-runner/src/dslManifest.ts +127 -0
- package/plugins/workflow-runner/src/expressions.ts +622 -0
- package/plugins/workflow-runner/src/index.js +13 -4
- package/plugins/workflow-runner/src/index.ts +338 -0
- package/plugins/workflow-runner/src/jsonPayload.ts +84 -0
- package/plugins/workflow-runner/src/loader.js +23 -0
- package/plugins/workflow-runner/src/loader.ts +721 -0
- package/plugins/workflow-runner/src/multimodal.js +2 -1
- package/plugins/workflow-runner/src/multimodal.ts +64 -0
- package/plugins/workflow-runner/src/recovery.ts +149 -0
- package/plugins/workflow-runner/src/runner.js +75 -659
- package/plugins/workflow-runner/src/runner.ts +604 -0
- package/plugins/workflow-runner/src/stepExecutors/agent.ts +234 -0
- package/plugins/workflow-runner/src/stepExecutors/assert.ts +50 -0
- package/plugins/workflow-runner/src/stepExecutors/echo.js +31 -0
- package/plugins/workflow-runner/src/stepExecutors/echo.ts +38 -0
- package/plugins/workflow-runner/src/stepExecutors/llm.ts +133 -0
- package/plugins/workflow-runner/src/stepExecutors/set.js +49 -0
- package/plugins/workflow-runner/src/stepExecutors/set.ts +56 -0
- package/plugins/workflow-runner/src/stepExecutors/skill.js +5 -6
- package/plugins/workflow-runner/src/stepExecutors/skill.ts +140 -0
- package/plugins/workflow-runner/src/stepExecutors/tool.js +80 -8
- package/plugins/workflow-runner/src/stepExecutors/tool.ts +256 -0
- package/plugins/workflow-runner/src/stepExecutors/verify.ts +68 -0
- package/plugins/workflow-runner/src/stepPipeline.js +277 -0
- package/plugins/workflow-runner/src/stepPipeline.ts +366 -0
- package/plugins/workflow-runner/src/taskIdentity.ts +405 -0
- package/plugins/workflow-runner/src/toolRuntime.js +48 -0
- package/plugins/workflow-runner/src/toolRuntime.ts +64 -0
- package/plugins/workflow-runner/src/types.js +37 -1
- package/plugins/workflow-runner/src/types.ts +602 -0
- package/plugins/workflow-runner/src/workflowState.ts +733 -0
- package/plugins/workflow-runner/test/agent.test.ts +587 -0
- package/plugins/workflow-runner/test/agentLlmError.test.ts +373 -0
- package/plugins/workflow-runner/test/bashBlacklist.sweep.test.ts +65 -0
- package/plugins/workflow-runner/test/captureMisbind.test.ts +99 -0
- package/plugins/workflow-runner/test/cli.e2e.test.ts +147 -0
- package/plugins/workflow-runner/test/context-files.test.ts +320 -0
- package/plugins/workflow-runner/test/e2e.test.ts +370 -0
- package/plugins/workflow-runner/test/engineRobustness.test.ts +226 -0
- package/plugins/workflow-runner/test/expressions.test.ts +397 -0
- package/plugins/workflow-runner/test/foundation.test.ts +126 -0
- package/plugins/workflow-runner/test/graceful.test.ts +139 -0
- package/plugins/workflow-runner/test/greedyInputs.load.test.ts +47 -0
- package/plugins/workflow-runner/test/hostCapability.test.ts +108 -0
- package/plugins/workflow-runner/test/illustrate.load.test.ts +183 -0
- package/plugins/workflow-runner/test/jsonPayload.test.ts +83 -0
- package/plugins/workflow-runner/test/loader.test.ts +617 -0
- package/plugins/workflow-runner/test/maxTurnsRetryDelay.test.ts +33 -0
- package/plugins/workflow-runner/test/multimodal.test.ts +342 -0
- package/plugins/workflow-runner/test/output-schema.test.ts +213 -0
- package/plugins/workflow-runner/test/parseWorkflowArgs.test.ts +87 -0
- package/plugins/workflow-runner/test/pluginRunner.isolation.test.ts +269 -0
- package/plugins/workflow-runner/test/ppt.load.test.ts +1220 -0
- package/plugins/workflow-runner/test/ralphLoop.e2e.test.ts +220 -0
- package/plugins/workflow-runner/test/recovery.test.ts +265 -0
- package/plugins/workflow-runner/test/runner.test.ts +911 -0
- package/plugins/workflow-runner/test/runnerPreflight.test.ts +379 -0
- package/plugins/workflow-runner/test/skillTurnDone.test.ts +71 -0
- package/plugins/workflow-runner/test/stateLifecycle.test.ts +150 -0
- package/plugins/workflow-runner/test/stepPipeline.test.ts +114 -0
- package/plugins/workflow-runner/test/taskArbitration.test.ts +338 -0
- package/plugins/workflow-runner/test/taskIdentity.test.ts +237 -0
- package/plugins/workflow-runner/test/taskLifecycle.test.ts +270 -0
- package/plugins/workflow-runner/test/toolArtifactOverwrite.test.ts +221 -0
- package/plugins/workflow-runner/test/toolCapabilityBoundary.test.ts +29 -0
- package/plugins/workflow-runner/test/toolRuntimeIntegration.test.ts +168 -0
- package/plugins/workflow-runner/test/webppt.load.test.ts +250 -0
- package/plugins/workflow-runner/test/word.load.test.ts +208 -0
- package/plugins/workflow-runner/test/workflows.smoke.test.ts +76 -0
- package/plugins/workflow-runner/test/yamlGuardConditions.test.ts +207 -0
- package/skills/browser-automation/SKILL.md +9 -19
- package/skills/web-crawler/SKILL.md +9 -11
- package/src/askBridge.ts +249 -0
- package/src/bootstrap/cwdArg.js +10 -3
- package/src/bootstrap/cwdArg.ts +31 -0
- package/src/bootstrap/workingDir.ts +48 -0
- package/src/cli/args.js +70 -7
- package/src/cli/args.ts +146 -0
- package/src/cli/computerUse.js +185 -0
- package/src/cli/computerUse.ts +221 -0
- package/src/cli/configMenu.js +274 -202
- package/src/cli/configMenu.tsx +521 -0
- package/src/cli/memoryAccess.js +45 -0
- package/src/cli/memoryAccess.ts +53 -0
- package/src/cli/print.js +119 -5
- package/src/cli/print.ts +597 -0
- package/src/cli/quickModelSetup.js +60 -0
- package/src/cli/quickModelSetup.tsx +96 -0
- package/src/cli/streamJson.js +80 -4
- package/src/cli/streamJson.ts +433 -0
- package/src/cli/wizards/advisorWizard.js +1 -0
- package/src/cli/wizards/advisorWizard.tsx +195 -0
- package/src/cli/wizards/agentRuntimeWizard.js +84 -0
- package/src/cli/wizards/agentRuntimeWizard.tsx +134 -0
- package/src/cli/wizards/browserWizard.js +55 -0
- package/src/cli/wizards/browserWizard.tsx +77 -0
- package/src/cli/wizards/contextAdvisorWizard.js +84 -0
- package/src/cli/wizards/contextAdvisorWizard.tsx +124 -0
- package/src/cli/wizards/fieldForm.js +7 -4
- package/src/cli/wizards/fieldForm.tsx +250 -0
- package/src/cli/wizards/imageWizard.js +4 -5
- package/src/cli/wizards/imageWizard.tsx +96 -0
- package/src/cli/wizards/openRouterWizard.tsx +48 -0
- package/src/cli/wizards/providerPresets.js +1 -8
- package/src/cli/wizards/providerPresets.ts +106 -0
- package/src/cli/wizards/providerWizard.js +152 -205
- package/src/cli/wizards/providerWizard.tsx +266 -0
- package/src/cli/wizards/searchWizard.tsx +47 -0
- package/src/cli/wizards/ttsWizard.js +4 -3
- package/src/cli/wizards/ttsWizard.tsx +61 -0
- package/src/config/configDefaults.js +25 -0
- package/src/config/configDefaults.ts +33 -0
- package/src/config/configDiagnostics.js +117 -0
- package/src/config/configDiagnostics.ts +166 -0
- package/src/config/configFile.js +52 -32
- package/src/config/configFile.ts +633 -0
- package/src/config/configManagement.js +126 -0
- package/src/config/configManagement.ts +159 -0
- package/src/config/configService.js +66 -11
- package/src/config/configService.ts +554 -0
- package/src/config/numericLimits.js +61 -0
- package/src/config/numericLimits.ts +80 -0
- package/src/config.ts +109 -0
- package/src/context/agentHome.ts +11 -0
- package/src/context/archive.ts +144 -0
- package/src/context/budgetPlan.js +54 -0
- package/src/context/budgetPlan.ts +88 -0
- package/src/context/compact.js +179 -106
- package/src/context/compact.ts +584 -0
- package/src/context/contextBundle.js +119 -0
- package/src/context/contextBundle.ts +176 -0
- package/src/context/contextLock.ts +84 -0
- package/src/context/microCompactLite.ts +218 -0
- package/src/context/persistContext.ts +177 -0
- package/src/context/reactiveCompact.js +19 -4
- package/src/context/reactiveCompact.ts +240 -0
- package/src/context/recentDirs.ts +42 -0
- package/src/context/sessionPath.ts +206 -0
- package/src/context/sessionRegistry.js +8 -2
- package/src/context/sessionRegistry.ts +414 -0
- package/src/context/snipCompact.ts +163 -0
- package/src/context/tokenCounter.ts +106 -0
- package/src/context/workspaceIndex.js +2 -2
- package/src/context/workspaceIndex.ts +751 -0
- package/src/entry.compiled.tsx +20 -0
- package/src/harness/claimValidation.js +9 -0
- package/src/harness/claimValidation.ts +22 -0
- package/src/harness/evidenceLedger.js +92 -0
- package/src/harness/evidenceLedger.ts +96 -0
- package/src/harness/stallGuard.js +60 -0
- package/src/harness/stallGuard.ts +81 -0
- package/src/humanIntervention.js +129 -0
- package/src/humanIntervention.ts +216 -0
- package/src/infra/verification.ts +295 -0
- package/src/irreversible/rules.js +216 -0
- package/src/irreversible/rules.ts +261 -0
- package/src/llm/client.js +40 -3
- package/src/llm/client.ts +621 -0
- package/src/llm/promptCache.js +27 -0
- package/src/llm/promptCache.ts +41 -0
- package/src/llm/providers/anthropicFormat.js +41 -5
- package/src/llm/providers/anthropicFormat.ts +290 -0
- package/src/llm/providers/openaiFormat.js +186 -8
- package/src/llm/providers/openaiFormat.ts +428 -0
- package/src/loop.js +614 -63
- package/src/loop.ts +1454 -0
- package/src/main.js +67 -10
- package/src/main.tsx +344 -0
- package/src/memory/codec.js +204 -0
- package/src/memory/codec.ts +249 -0
- package/src/memory/constants.js +34 -0
- package/src/memory/constants.ts +50 -0
- package/src/memory/episodicMemory.js +684 -0
- package/src/memory/episodicMemory.ts +815 -0
- package/src/memory/fileStore.js +148 -0
- package/src/memory/fileStore.ts +184 -0
- package/src/memory/memoryService.js +570 -0
- package/src/memory/memoryService.ts +859 -0
- package/src/memory/migration.js +128 -0
- package/src/memory/migration.ts +160 -0
- package/src/memory/repository.js +789 -0
- package/src/memory/repository.ts +893 -0
- package/src/memory/retrieval.js +108 -0
- package/src/memory/retrieval.ts +145 -0
- package/src/memory/searchIndex.js +107 -0
- package/src/memory/searchIndex.ts +153 -0
- package/src/memory/topicView.js +82 -0
- package/src/memory/topicView.ts +95 -0
- package/src/memory/turnJournal.js +95 -0
- package/src/memory/turnJournal.ts +120 -0
- package/src/memory/types.js +2 -0
- package/src/memory/types.ts +186 -0
- package/src/messageQueue.ts +123 -0
- package/src/multimodal.js +128 -46
- package/src/multimodal.ts +349 -0
- package/src/plugin-sdk.js +21 -1
- package/src/plugin-sdk.ts +134 -0
- package/src/plugins/builtinPluginIds.js +47 -0
- package/src/plugins/builtinPluginIds.ts +51 -0
- package/src/plugins/builtinRegistry.ts +43 -0
- package/src/plugins/commandRouter.js +40 -26
- package/src/plugins/commandRouter.ts +261 -0
- package/src/plugins/hookEngine.ts +341 -0
- package/src/plugins/pluginApi.ts +133 -0
- package/src/plugins/pluginLifecycle.ts +34 -0
- package/src/plugins/pluginLoader.ts +147 -0
- package/src/plugins/pluginManifest.js +127 -0
- package/src/plugins/pluginManifest.ts +152 -0
- package/src/plugins/pluginRunner.js +47 -2
- package/src/plugins/pluginRunner.ts +207 -0
- package/src/plugins/transcript.ts +208 -0
- package/src/prompts/lint.js +169 -0
- package/src/prompts/lint.ts +220 -0
- package/src/prompts/pluginList.js +32 -16
- package/src/prompts/pluginList.ts +86 -0
- package/src/prompts/policyRegistry.js +318 -0
- package/src/prompts/policyRegistry.ts +358 -0
- package/src/prompts/projectInstructions.js +24 -0
- package/src/prompts/projectInstructions.ts +81 -0
- package/src/prompts/promptAssembly.js +311 -202
- package/src/prompts/promptAssembly.ts +510 -0
- package/src/prompts/skillList.js +106 -45
- package/src/prompts/skillList.ts +198 -0
- package/src/prompts/system.js +31 -6
- package/src/prompts/system.ts +81 -0
- package/src/runtime/agentRuntimeContext.js +53 -0
- package/src/runtime/agentRuntimeContext.ts +112 -0
- package/src/session/runAgentTurn.js +71 -12
- package/src/session/runAgentTurn.ts +181 -0
- package/src/session/runTurn.js +29 -0
- package/src/session/runTurn.ts +160 -0
- package/src/session/runtimeStore.js +149 -0
- package/src/session/runtimeStore.ts +197 -0
- package/src/session/sessionState.js +79 -3
- package/src/session/sessionState.ts +134 -0
- package/src/toolGate.ts +50 -0
- package/src/tools/advisor/advisor.js +76 -15
- package/src/tools/advisor/advisor.ts +512 -0
- package/src/tools/agent/agent.js +245 -29
- package/src/tools/agent/agent.ts +837 -0
- package/src/tools/agent/agentTaskService.js +60 -0
- package/src/tools/agent/agentTaskService.ts +113 -0
- package/src/tools/agent/agentTypes.js +20 -8
- package/src/tools/agent/agentTypes.ts +94 -0
- package/src/tools/agent/coordinator.ts +111 -0
- package/src/tools/agent/worktree.ts +296 -0
- package/src/tools/ask/ask.js +17 -0
- package/src/tools/ask/ask.ts +122 -0
- package/src/tools/bash/attachImage.js +223 -0
- package/src/tools/bash/attachImage.ts +281 -0
- package/src/tools/bash/bash.js +132 -14
- package/src/tools/bash/bash.ts +642 -0
- package/src/tools/bash/semantics.ts +103 -0
- package/src/tools/bash/warnings.js +17 -11
- package/src/tools/bash/warnings.ts +117 -0
- package/src/tools/capabilities.js +42 -0
- package/src/tools/capabilities.ts +69 -0
- package/src/tools/computeruse/accessibilityPermission.js +261 -0
- package/src/tools/computeruse/accessibilityPermission.ts +294 -0
- package/src/tools/computeruse/axSearch.js +96 -0
- package/src/tools/computeruse/axSearch.ts +120 -0
- package/src/tools/computeruse/axSnap.js +272 -0
- package/src/tools/computeruse/axSnap.ts +349 -0
- package/src/tools/computeruse/capabilityLabels.js +95 -0
- package/src/tools/computeruse/capabilityLabels.ts +115 -0
- package/src/tools/computeruse/computerUseService.js +2235 -0
- package/src/tools/computeruse/computerUseService.ts +2686 -0
- package/src/tools/computeruse/computeruse.js +2742 -0
- package/src/tools/computeruse/computeruse.ts +3265 -0
- package/src/tools/computeruse/diagnosticTrace.js +154 -0
- package/src/tools/computeruse/diagnosticTrace.ts +195 -0
- package/src/tools/computeruse/diagnostics.js +369 -0
- package/src/tools/computeruse/diagnostics.ts +453 -0
- package/src/tools/computeruse/grants.js +53 -0
- package/src/tools/computeruse/grants.ts +70 -0
- package/src/tools/computeruse/humanBoundary.js +159 -0
- package/src/tools/computeruse/humanBoundary.ts +199 -0
- package/src/tools/computeruse/intervention.js +77 -0
- package/src/tools/computeruse/intervention.ts +110 -0
- package/src/tools/computeruse/manualSchema.js +709 -0
- package/src/tools/computeruse/manualSchema.ts +916 -0
- package/src/tools/computeruse/observationImages.js +705 -0
- package/src/tools/computeruse/observationImages.ts +889 -0
- package/src/tools/computeruse/protocol.js +60 -0
- package/src/tools/computeruse/protocol.ts +515 -0
- package/src/tools/computeruse/telemetryLog.js +57 -0
- package/src/tools/computeruse/telemetryLog.ts +67 -0
- package/src/tools/computeruse/vision/appGuide.js +325 -0
- package/src/tools/computeruse/vision/appGuide.ts +482 -0
- package/src/tools/computeruse/vision/focus.js +291 -0
- package/src/tools/computeruse/vision/focus.ts +382 -0
- package/src/tools/computeruse/vision/frames.js +248 -0
- package/src/tools/computeruse/vision/frames.ts +329 -0
- package/src/tools/computeruse/vision/geometry.js +131 -0
- package/src/tools/computeruse/vision/geometry.ts +163 -0
- package/src/tools/computeruse/vision/imaging.js +201 -0
- package/src/tools/computeruse/vision/imaging.ts +281 -0
- package/src/tools/computeruse/vision/png.js +274 -0
- package/src/tools/computeruse/vision/png.ts +317 -0
- package/src/tools/computeruse/vision/raster.js +320 -0
- package/src/tools/computeruse/vision/raster.ts +408 -0
- package/src/tools/computeruse/vision/settle.js +131 -0
- package/src/tools/computeruse/vision/settle.ts +220 -0
- package/src/tools/computeruse/vision/telemetry.js +196 -0
- package/src/tools/computeruse/vision/telemetry.ts +241 -0
- package/src/tools/computeruse/visionOcr.js +115 -0
- package/src/tools/computeruse/visionOcr.ts +128 -0
- package/src/tools/computeruse/waitFor.js +237 -0
- package/src/tools/computeruse/waitFor.ts +291 -0
- package/src/tools/download/download.js +10 -6
- package/src/tools/download/download.ts +187 -0
- package/src/tools/edit/edit.js +30 -18
- package/src/tools/edit/edit.ts +349 -0
- package/src/tools/edit/multi-edit.js +25 -14
- package/src/tools/edit/multi-edit.ts +223 -0
- package/src/tools/effectiveToolSet.js +73 -0
- package/src/tools/effectiveToolSet.ts +91 -0
- package/src/tools/genimage/genimage.ts +257 -0
- package/src/tools/genspeech/genspeech.ts +83 -0
- package/src/tools/glob/glob.js +176 -29
- package/src/tools/glob/glob.ts +283 -0
- package/src/tools/grep/grep.js +61 -19
- package/src/tools/grep/grep.ts +239 -0
- package/src/tools/grep/rgPath.ts +206 -0
- package/src/tools/index.js +99 -5
- package/src/tools/index.ts +293 -0
- package/src/tools/lsp/config.js +113 -0
- package/src/tools/lsp/config.ts +113 -0
- package/src/tools/lsp/lsp.js +256 -0
- package/src/tools/lsp/lsp.ts +274 -0
- package/src/tools/lsp/service.js +303 -0
- package/src/tools/lsp/service.ts +296 -0
- package/src/tools/memory/memory.js +520 -0
- package/src/tools/memory/memory.ts +625 -0
- package/src/tools/memory/policy.js +53 -0
- package/src/tools/memory/policy.ts +72 -0
- package/src/tools/notebook/notebookEdit.js +114 -0
- package/src/tools/notebook/notebookEdit.ts +126 -0
- package/src/tools/powershell/powershell.js +210 -0
- package/src/tools/powershell/powershell.ts +239 -0
- package/src/tools/presentresult/presentresult.js +145 -0
- package/src/tools/presentresult/presentresult.ts +156 -0
- package/src/tools/read/read.js +371 -163
- package/src/tools/read/read.ts +558 -0
- package/src/tools/shared/diffSummary.js +44 -0
- package/src/tools/shared/diffSummary.ts +63 -0
- package/src/tools/shared/fileActivity.js +51 -0
- package/src/tools/shared/fileActivity.ts +66 -0
- package/src/tools/shared/fileMutationBus.js +13 -0
- package/src/tools/shared/fileMutationBus.ts +14 -0
- package/src/tools/shared/fileState.js +73 -65
- package/src/tools/shared/fileState.ts +145 -0
- package/src/tools/shared/fileUtils.js +81 -4
- package/src/tools/shared/fileUtils.ts +504 -0
- package/src/tools/shared/killTree.ts +50 -0
- package/src/tools/shared/permanentDeleteGuard.js +26 -0
- package/src/tools/shared/permanentDeleteGuard.ts +34 -0
- package/src/tools/shared/schemas.ts +20 -0
- package/src/tools/shared/toolOutputStore.js +97 -0
- package/src/tools/shared/toolOutputStore.ts +110 -0
- package/src/tools/skill/skill.js +86 -0
- package/src/tools/skill/skill.ts +94 -0
- package/src/tools/snip/snip.js +67 -0
- package/src/tools/snip/snip.ts +80 -0
- package/src/tools/tasks/backgroundTaskService.js +275 -0
- package/src/tools/tasks/backgroundTaskService.ts +369 -0
- package/src/tools/tasks/processEvidence.js +24 -0
- package/src/tools/tasks/processEvidence.ts +34 -0
- package/src/tools/tasks/taskManagement.js +163 -0
- package/src/tools/tasks/taskManagement.ts +180 -0
- package/src/tools/tasks/taskOutput.js +113 -0
- package/src/tools/tasks/taskOutput.ts +145 -0
- package/src/tools/tasks/taskStop.js +74 -0
- package/src/tools/tasks/taskStop.ts +99 -0
- package/src/tools/tasks/taskStore.js +46 -0
- package/src/tools/tasks/taskStore.ts +77 -0
- package/src/tools/terminal/terminalCapture.js +167 -0
- package/src/tools/terminal/terminalCapture.ts +179 -0
- package/src/tools/trash/trash.js +233 -0
- package/src/tools/trash/trash.ts +283 -0
- package/src/tools/types.js +1 -1
- package/src/tools/types.ts +24 -0
- package/src/tools/webbrowser/agentBrowserPath.ts +286 -0
- package/src/tools/webbrowser/browser.js +214 -11
- package/src/tools/webbrowser/browser.ts +293 -0
- package/src/tools/webbrowser/browserControl.js +153 -48
- package/src/tools/webbrowser/browserControl.ts +262 -0
- package/src/tools/webbrowser/browserDaemon.js +147 -39
- package/src/tools/webbrowser/browserDaemon.ts +270 -0
- package/src/tools/webbrowser/browserOutcome.js +273 -0
- package/src/tools/webbrowser/browserOutcome.ts +306 -0
- package/src/tools/webbrowser/browserRunRegistry.js +150 -0
- package/src/tools/webbrowser/browserRunRegistry.ts +179 -0
- package/src/tools/webbrowser/browserService.js +20 -6
- package/src/tools/webbrowser/browserService.ts +56 -0
- package/src/tools/webbrowser/browserStream.js +30 -1
- package/src/tools/webbrowser/browserStream.ts +216 -0
- package/src/tools/webbrowser/browserTabs.js +143 -0
- package/src/tools/webbrowser/browserTabs.ts +210 -0
- package/src/tools/webbrowser/webbrowser.js +831 -150
- package/src/tools/webbrowser/webbrowser.ts +1537 -0
- package/src/tools/webfetch/preapproved.ts +274 -0
- package/src/tools/webfetch/webfetch.js +24 -23
- package/src/tools/webfetch/webfetch.ts +383 -0
- package/src/tools/websearch/websearch.js +12 -11
- package/src/tools/websearch/websearch.ts +292 -0
- package/src/tools/worktree/sessionWorktree.js +128 -0
- package/src/tools/worktree/sessionWorktree.ts +158 -0
- package/src/tools/write/write.js +27 -44
- package/src/tools/write/write.ts +136 -0
- package/src/types.ts +960 -0
- package/src/ui/App.js +216 -12
- package/src/ui/App.tsx +879 -0
- package/src/ui/AskQuestion.tsx +300 -0
- package/src/ui/InputBox.js +77 -1
- package/src/ui/InputBox.tsx +567 -0
- package/src/ui/LiveArea.tsx +344 -0
- package/src/ui/MessageList.js +27 -6
- package/src/ui/MessageList.tsx +559 -0
- package/src/ui/ModelPicker.tsx +107 -0
- package/src/ui/QueuedMessagesBanner.tsx +51 -0
- package/src/ui/Root.js +6 -8
- package/src/ui/Root.tsx +100 -0
- package/src/ui/SessionPicker.tsx +169 -0
- package/src/ui/StatusLine.js +22 -1
- package/src/ui/StatusLine.tsx +145 -0
- package/src/ui/WorkspacePicker.tsx +84 -0
- package/src/ui/advisorCommand.js +54 -0
- package/src/ui/advisorCommand.ts +63 -0
- package/src/ui/computerCommand.js +19 -0
- package/src/ui/computerCommand.ts +35 -0
- package/src/ui/figures.ts +45 -0
- package/src/ui/hooks/askSlot.ts +112 -0
- package/src/ui/hooks/useChat.js +271 -7
- package/src/ui/hooks/useChat.ts +1578 -0
- package/src/ui/hooks/useInputHistory.ts +235 -0
- package/src/ui/hooks/usePasteHandler.ts +220 -0
- package/src/ui/hooks/useTerminalSize.ts +41 -0
- package/src/ui/hooks/useTextBuffer.ts +108 -0
- package/src/ui/hooks/useTokenUsage.ts +44 -0
- package/src/ui/liveViewport.ts +189 -0
- package/src/ui/markdown.ts +230 -0
- package/src/ui/textBuffer.ts +239 -0
- package/src/ui/theme.ts +35 -0
- package/src/utils/clipboardImage.js +358 -0
- package/src/utils/clipboardImage.ts +420 -0
- package/src/utils/debugLog.ts +50 -0
- package/src/utils/greenRoot.ts +35 -0
- package/src/utils/packageRoot.ts +40 -0
- package/src/utils/pathContains.js +28 -0
- package/src/utils/pathContains.ts +31 -0
- package/src/utils/resourcePaths.ts +71 -0
- package/src/utils/stripThink.ts +49 -0
- package/src/utils/zodToJson.ts +73 -0
- package/src/web/browserBridge.js +365 -66
- package/src/web/browserBridge.ts +672 -0
- package/src/web/protocol.ts +1804 -0
- package/vendor/computer-use/arm64-darwin/cu-helperd +0 -0
- package/workflows/ppt.yaml +13 -2
- package/workflows/wechat-reading-shots.yaml +315 -0
- package/workflows/word.yaml +11 -1
- package/skills/docx/scripts/office/helpers/__pycache__/__init__.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/helpers/__pycache__/merge_runs.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/helpers/__pycache__/simplify_redlines.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/validators/__pycache__/__init__.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/validators/__pycache__/base.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/validators/__pycache__/docx.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/validators/__pycache__/pptx.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/validators/__pycache__/redlining.cpython-314.pyc +0 -0
- package/skills/image-stats/scripts/__pycache__/image_stats.cpython-314.pyc +0 -0
- package/skills/image-stats/scripts/__pycache__/image_stats_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/assemble_material.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/assemble_material_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/chart_sanity_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/check_language_policy.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/check_ui_artifact.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/check_ui_artifact_pptx_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/deck_pages_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/deck_pages_check_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/deck_visual_style_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/deck_visual_style_check_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_budget_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_budget_check_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_repair_hints.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_repair_hints_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_style_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_style_check_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/draft_coverage_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/extract_source_assets.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/extract_source_assets_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/generated_image_review_collect.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/generated_image_review_collect_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/image_plan_lint.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/image_plan_lint_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/image_prompt_rewrite.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/image_prompt_rewrite_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/layout_balance.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/layout_balance_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/normalize_design_json.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/normalize_design_json_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/plan_source_layout.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/plan_source_layout_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/resolve_source_hint.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/resolve_source_hint_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/resolve_source_input.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/resolve_source_input_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/scaffold_ui_artifact.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/source_usage_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/source_usage_check_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/text_readability_pixel.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/visual_quality_gate.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/visual_quality_gate_test.cpython-314.pyc +0 -0
- /package/skills/ai-image/scripts/{generate_test.mjs → generate.selftest.mjs} +0 -0
- /package/skills/ai-image/scripts/{generate_from_plan_test.mjs → generate_from_plan.selftest.mjs} +0 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ============================================================
|
|
3
|
+
* src/plugin-sdk.ts —— 插件作者的稳定 import 门面
|
|
4
|
+
* ------------------------------------------------------------
|
|
5
|
+
* Drop-in 插件契约的"窄门":插件根目录下的 plugin.ts 只允许从
|
|
6
|
+
* '../../src/plugin-sdk.js' 取运行时(NodeNext 标准,Bun 自动回退到 .ts
|
|
7
|
+
* 源文件,Node 跑 install 后编译产物),不直接访问 src/ 内部路径。
|
|
8
|
+
*
|
|
9
|
+
* 好处:
|
|
10
|
+
* - 框架内部重构(loop.ts / llm/client.ts / tools/* 移动)不破坏插件
|
|
11
|
+
* - 插件作者只需记一个 import 源
|
|
12
|
+
* - 暴露面收口(这里没的 API 不开放给插件)
|
|
13
|
+
*
|
|
14
|
+
* 零运行时开销:纯 re-export,TS 编译后等价于直接 import。
|
|
15
|
+
* ============================================================
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
// --- 运行时入口 ---
|
|
19
|
+
export { runQuery } from './loop.js';
|
|
20
|
+
export type { RunQueryOptions } from './loop.js';
|
|
21
|
+
export type { ToolGate, ToolGateRequest, ToolGateDecision } from './toolGate.js';
|
|
22
|
+
export { runAgentTurn } from './session/runAgentTurn.js';
|
|
23
|
+
export type { RunAgentTurnOptions, RunAgentTurnResult } from './session/runAgentTurn.js';
|
|
24
|
+
|
|
25
|
+
export { chat } from './llm/client.js';
|
|
26
|
+
export {
|
|
27
|
+
derivePromptCacheContext,
|
|
28
|
+
} from './llm/promptCache.js';
|
|
29
|
+
|
|
30
|
+
export { ALL_TOOLS, executeTool, getToolByName } from './tools/index.js';
|
|
31
|
+
export { shutdownAllLsp } from './tools/lsp/service.js';
|
|
32
|
+
|
|
33
|
+
// --- Computer Use ---
|
|
34
|
+
//
|
|
35
|
+
// 桌面操作的**知识与命令面**住在 `plugins/computer_use/`,可信执行层住在内核
|
|
36
|
+
// (`src/tools/computeruse/`)。这里**只**开放只读诊断门面:
|
|
37
|
+
//
|
|
38
|
+
// ⚠️ 曾经这里导出的是完整的 `computerUseService`,而那个对象的 `request()`
|
|
39
|
+
// 能派发 click / type / file_drop —— 一个「只做诊断与知识管理」的插件不该
|
|
40
|
+
// 拿得到操作鼠标键盘的能力。注释当时宣称「只开放这几件事」,代码没做到。
|
|
41
|
+
// 别再把 service 加回来。
|
|
42
|
+
export { computerUseDiagnostics } from './tools/computeruse/diagnostics.js';
|
|
43
|
+
export { describeCapabilities } from './tools/computeruse/capabilityLabels.js';
|
|
44
|
+
export type { CapabilityLabel, CapabilityState } from './tools/computeruse/capabilityLabels.js';
|
|
45
|
+
export type {
|
|
46
|
+
ManualDraft,
|
|
47
|
+
ManualSource,
|
|
48
|
+
} from './tools/computeruse/diagnostics.js';
|
|
49
|
+
export { readRecentComputerUseAudit } from './cli/computerUse.js';
|
|
50
|
+
export { readComputerUseTelemetryReport } from './tools/computeruse/telemetryLog.js';
|
|
51
|
+
export {
|
|
52
|
+
matchGuide,
|
|
53
|
+
describeMatch,
|
|
54
|
+
loadAllAppManuals,
|
|
55
|
+
} from './tools/computeruse/vision/appGuide.js';
|
|
56
|
+
export type {
|
|
57
|
+
LoadedManuals,
|
|
58
|
+
} from './tools/computeruse/vision/appGuide.js';
|
|
59
|
+
export {
|
|
60
|
+
EMPTY_MANUAL,
|
|
61
|
+
validateManual,
|
|
62
|
+
} from './tools/computeruse/manualSchema.js';
|
|
63
|
+
export type {
|
|
64
|
+
ManualFlow,
|
|
65
|
+
} from './tools/computeruse/manualSchema.js';
|
|
66
|
+
export type {
|
|
67
|
+
ComputerUseResponse,
|
|
68
|
+
} from './tools/computeruse/protocol.js';
|
|
69
|
+
|
|
70
|
+
// pre-read 守卫状态登记:tool 步覆盖「声明产物」时用来解除内核「先读后写 / 截断禁写」
|
|
71
|
+
// 守卫(确定性步的 args 写死、模型没机会先 Read)。详见 stepExecutors/tool.ts。
|
|
72
|
+
export { recordRead } from './tools/shared/fileState.js';
|
|
73
|
+
|
|
74
|
+
export { getWorkingDir } from './bootstrap/workingDir.js';
|
|
75
|
+
export { dlog } from './utils/debugLog.js';
|
|
76
|
+
// <think> 思维链剥离:内核与 workflow-runner 共享(原住 agentCommon.ts,
|
|
77
|
+
// Agent 子任务工具也需要 → 上移内核,插件经此 re-export)。
|
|
78
|
+
export { stripThinkBlocks } from './utils/stripThink.js';
|
|
79
|
+
// buildFullSystemPrompt is retained for compatibility. New long-running hosts should keep
|
|
80
|
+
// buildBaseSystemPrompt stable and pass buildTransientContext separately for each turn.
|
|
81
|
+
export {
|
|
82
|
+
buildBaseSystemPrompt,
|
|
83
|
+
buildTransientContext,
|
|
84
|
+
buildTransientPromptBundle,
|
|
85
|
+
} from './prompts/system.js';
|
|
86
|
+
export type { PromptEnvelope, PromptSurface } from './prompts/promptAssembly.js';
|
|
87
|
+
export type { ContextBundle } from './context/contextBundle.js';
|
|
88
|
+
export {
|
|
89
|
+
createAgentRuntimeContext,
|
|
90
|
+
filterToolsForRuntime,
|
|
91
|
+
} from './runtime/agentRuntimeContext.js';
|
|
92
|
+
export type {
|
|
93
|
+
AgentRuntimeContext,
|
|
94
|
+
} from './runtime/agentRuntimeContext.js';
|
|
95
|
+
export { getResourceSearchPaths } from './utils/resourcePaths.js';
|
|
96
|
+
export type { ResourceName } from './utils/resourcePaths.js';
|
|
97
|
+
|
|
98
|
+
// 确定性检查设施:verify 步(shell/file_exists/file_contains/test_count)经此跑校验。
|
|
99
|
+
export { parseCheckString, runVerification } from './infra/verification.js';
|
|
100
|
+
export type { Check } from './infra/verification.js';
|
|
101
|
+
|
|
102
|
+
export { triggerHook } from './plugins/hookEngine.js';
|
|
103
|
+
export type { HookEventName, HookDecision } from './plugins/hookEngine.js';
|
|
104
|
+
|
|
105
|
+
export { createSessionState } from './session/sessionState.js';
|
|
106
|
+
export type { SessionState } from './session/sessionState.js';
|
|
107
|
+
|
|
108
|
+
// 会话文件是否真实存在(含 default session 的 legacy 路径回退):
|
|
109
|
+
// cron-runner 等需要在发起回合前判断"绑定的 session 是否还在"时用它,
|
|
110
|
+
// 不要绕过 legacy 回退逻辑自己拼路径。
|
|
111
|
+
export { resolveSessionFile } from './context/sessionPath.js';
|
|
112
|
+
|
|
113
|
+
// --- 类型 ---
|
|
114
|
+
export type {
|
|
115
|
+
ImageDetail,
|
|
116
|
+
ImageInputSpec,
|
|
117
|
+
Message,
|
|
118
|
+
Provider,
|
|
119
|
+
LoopEvent,
|
|
120
|
+
LlmStreamEvent,
|
|
121
|
+
PromptCacheContext,
|
|
122
|
+
Tool,
|
|
123
|
+
// 插件需要它来组装 executeTool 的第四参(宿主授权上下文按需切片转发)。
|
|
124
|
+
// 不导出的话插件只能绕过门面直接 import 内核,那正是门面要避免的。
|
|
125
|
+
ToolCallContext,
|
|
126
|
+
ToolResult,
|
|
127
|
+
} from './types.js';
|
|
128
|
+
|
|
129
|
+
export type {
|
|
130
|
+
PluginApi,
|
|
131
|
+
PluginContext,
|
|
132
|
+
PluginEvent,
|
|
133
|
+
PluginRuntimeContext,
|
|
134
|
+
} from './plugins/pluginApi.js';
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ============================================================
|
|
3
|
+
* src/plugins/builtinPluginIds.ts —— 内置插件清单 / 插件资产目录(单一真值)
|
|
4
|
+
* ------------------------------------------------------------
|
|
5
|
+
* 这个文件存在的唯一理由:同一份清单此前被抄在四个地方(builtinRegistry.ts、
|
|
6
|
+
* scripts/build-green.ts、minimal-desktop/scripts/build-sidecar.ts、以及各测试),
|
|
7
|
+
* 而它们**必须**同时更新才正确 —— 漏一处的失败方式全是静默的:
|
|
8
|
+
*
|
|
9
|
+
* · 漏注册 rich 插件(真实发生过:computer_use)→ 绿色版/sidecar 里
|
|
10
|
+
* `loadPluginApi` 找不到 runCommand → 静默回退成声明式 markdown →
|
|
11
|
+
* `/computeruse` 从「确定性诊断命令」变成「让 LLM 自由发挥的 prompt」。
|
|
12
|
+
* 没有报错、没有告警,只有行为变了。
|
|
13
|
+
* · 漏拷资产目录(真实发生过:`app/`)→ ComputerUse 对每个应用都报
|
|
14
|
+
* 「未找到说明书」,同样零构建期错误。
|
|
15
|
+
*
|
|
16
|
+
* 故意做成**不 import 任何东西的中立叶子模块**:构建脚本(bun 直接跑 .ts)、
|
|
17
|
+
* 单测和运行时代码都能安全 import 它,不会顺链拖进 plugin-sdk / ink 之类的重依赖。
|
|
18
|
+
* ============================================================
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* 内置 rich 插件(带 `plugin.ts` 执行器的那些)的 id 清单。
|
|
22
|
+
*
|
|
23
|
+
* id 必须**等于插件目录名**(`plugins/<id>/` 的 `<id>`),因为 pluginLoader 用
|
|
24
|
+
* `basename(pluginRoot)` 查内置注册表。注意 `computer_use` 是下划线不是连字符 ——
|
|
25
|
+
* 目录名怎么写这里就怎么写,别顺手「统一风格」,改了就查不到了。
|
|
26
|
+
*
|
|
27
|
+
* `test/pluginBuiltinRegistry.test.ts` 把它和磁盘上实际存在 `plugin.ts` 的插件目录
|
|
28
|
+
* 做全等断言:多一个少一个都红。
|
|
29
|
+
*/
|
|
30
|
+
export const BUILTIN_PLUGIN_IDS = [
|
|
31
|
+
'workflow-runner',
|
|
32
|
+
'cron-runner',
|
|
33
|
+
'computer_use',
|
|
34
|
+
];
|
|
35
|
+
/**
|
|
36
|
+
* 插件里需要随包铺到磁盘的资产子目录(数据,不是代码)。
|
|
37
|
+
*
|
|
38
|
+
* 为什么不能靠打包器:这些目录里是 markdown / json 声明,没有任何 import 指向
|
|
39
|
+
* 它们,`bun --compile` 的依赖图看不见 → 只能由各构建脚本显式拷贝。绿色版
|
|
40
|
+
* (build-green.ts)与 Desktop sidecar(build-sidecar.ts)各拷一次,两处必须一致。
|
|
41
|
+
*/
|
|
42
|
+
export const PLUGIN_ASSET_DIRS = [
|
|
43
|
+
'.claude-plugin',
|
|
44
|
+
'commands',
|
|
45
|
+
'hooks',
|
|
46
|
+
'app',
|
|
47
|
+
];
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ============================================================
|
|
3
|
+
* src/plugins/builtinPluginIds.ts —— 内置插件清单 / 插件资产目录(单一真值)
|
|
4
|
+
* ------------------------------------------------------------
|
|
5
|
+
* 这个文件存在的唯一理由:同一份清单此前被抄在四个地方(builtinRegistry.ts、
|
|
6
|
+
* scripts/build-green.ts、minimal-desktop/scripts/build-sidecar.ts、以及各测试),
|
|
7
|
+
* 而它们**必须**同时更新才正确 —— 漏一处的失败方式全是静默的:
|
|
8
|
+
*
|
|
9
|
+
* · 漏注册 rich 插件(真实发生过:computer_use)→ 绿色版/sidecar 里
|
|
10
|
+
* `loadPluginApi` 找不到 runCommand → 静默回退成声明式 markdown →
|
|
11
|
+
* `/computeruse` 从「确定性诊断命令」变成「让 LLM 自由发挥的 prompt」。
|
|
12
|
+
* 没有报错、没有告警,只有行为变了。
|
|
13
|
+
* · 漏拷资产目录(真实发生过:`app/`)→ ComputerUse 对每个应用都报
|
|
14
|
+
* 「未找到说明书」,同样零构建期错误。
|
|
15
|
+
*
|
|
16
|
+
* 故意做成**不 import 任何东西的中立叶子模块**:构建脚本(bun 直接跑 .ts)、
|
|
17
|
+
* 单测和运行时代码都能安全 import 它,不会顺链拖进 plugin-sdk / ink 之类的重依赖。
|
|
18
|
+
* ============================================================
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 内置 rich 插件(带 `plugin.ts` 执行器的那些)的 id 清单。
|
|
23
|
+
*
|
|
24
|
+
* id 必须**等于插件目录名**(`plugins/<id>/` 的 `<id>`),因为 pluginLoader 用
|
|
25
|
+
* `basename(pluginRoot)` 查内置注册表。注意 `computer_use` 是下划线不是连字符 ——
|
|
26
|
+
* 目录名怎么写这里就怎么写,别顺手「统一风格」,改了就查不到了。
|
|
27
|
+
*
|
|
28
|
+
* `test/pluginBuiltinRegistry.test.ts` 把它和磁盘上实际存在 `plugin.ts` 的插件目录
|
|
29
|
+
* 做全等断言:多一个少一个都红。
|
|
30
|
+
*/
|
|
31
|
+
export const BUILTIN_PLUGIN_IDS = [
|
|
32
|
+
'workflow-runner',
|
|
33
|
+
'cron-runner',
|
|
34
|
+
'computer_use',
|
|
35
|
+
] as const;
|
|
36
|
+
|
|
37
|
+
export type BuiltinPluginId = (typeof BUILTIN_PLUGIN_IDS)[number];
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 插件里需要随包铺到磁盘的资产子目录(数据,不是代码)。
|
|
41
|
+
*
|
|
42
|
+
* 为什么不能靠打包器:这些目录里是 markdown / json 声明,没有任何 import 指向
|
|
43
|
+
* 它们,`bun --compile` 的依赖图看不见 → 只能由各构建脚本显式拷贝。绿色版
|
|
44
|
+
* (build-green.ts)与 Desktop sidecar(build-sidecar.ts)各拷一次,两处必须一致。
|
|
45
|
+
*/
|
|
46
|
+
export const PLUGIN_ASSET_DIRS = [
|
|
47
|
+
'.claude-plugin',
|
|
48
|
+
'commands',
|
|
49
|
+
'hooks',
|
|
50
|
+
'app',
|
|
51
|
+
] as const;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ============================================================
|
|
3
|
+
* src/plugins/builtinRegistry.ts —— 内置插件静态注册(仅绿色版 compile 用)
|
|
4
|
+
* ------------------------------------------------------------
|
|
5
|
+
* 仅被 `src/entry.compiled.tsx`(bun --compile 入口)import。
|
|
6
|
+
*
|
|
7
|
+
* 作用:静态 import 内置 rich 插件的 plugin.ts,让 bun 在 `--compile` 时把
|
|
8
|
+
* 它们的执行器整树(含各自 `./src/*` 与框架 `../../src/plugin-sdk.ts`)一并
|
|
9
|
+
* 打进单个可执行文件;再注册进 pluginLoader 的内置表,供绿色目录里"只铺了
|
|
10
|
+
* 声明式部分(plugin.json + commands/)"的插件在运行时回退命中执行器。
|
|
11
|
+
*
|
|
12
|
+
* ⚠️ dev / npm 模式**绝不 import 本文件**(入口是 src/main.tsx)→ 注册表为空
|
|
13
|
+
* → pluginLoader 走原磁盘动态加载,行为逐字节不变。tsconfig.json 已 exclude
|
|
14
|
+
* 本文件与 entry.compiled.tsx,故 `tsc --build` 不产出二者 .js,npm tarball 不变。
|
|
15
|
+
*
|
|
16
|
+
* key 必须等于插件目录名(`plugins/<id>/` 的 `<id>`),与 pluginLoader 里
|
|
17
|
+
* `basename(pluginRoot)` 对齐。清单本身住在 `builtinPluginIds.ts`。
|
|
18
|
+
*
|
|
19
|
+
* ⚠️ 为什么是 `Record<BuiltinPluginId, PluginApi>` 而不是几行 setBuiltinPluginApi:
|
|
20
|
+
* 漏一个插件的后果是**静默降级**(找不到执行器 → 回退声明式 markdown →
|
|
21
|
+
* 确定性命令悄悄变成 LLM prompt),没有任何报错。真实发生过:computer_use 有
|
|
22
|
+
* plugin.ts 却没登记在这里。用 Record 之后,清单里加了 id 而这里少一个 import
|
|
23
|
+
* 就直接类型不过 —— 编译期挡住,比事后扫源码字符串硬得多。
|
|
24
|
+
*
|
|
25
|
+
* 注意 tsconfig.json 虽然 exclude 了本文件(不进 npm tarball),但
|
|
26
|
+
* tsconfig.typecheck.json 不继承 include/exclude,`bun run typecheck` 照查不误。
|
|
27
|
+
* ============================================================
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
import computerUseApi from '../../plugins/computer_use/plugin.js';
|
|
31
|
+
import cronApi from '../../plugins/cron-runner/plugin.js';
|
|
32
|
+
import workflowApi from '../../plugins/workflow-runner/plugin.js';
|
|
33
|
+
import { BUILTIN_PLUGIN_IDS, type BuiltinPluginId } from './builtinPluginIds.js';
|
|
34
|
+
import type { PluginApi } from './pluginApi.js';
|
|
35
|
+
import { setBuiltinPluginApi } from './pluginLoader.js';
|
|
36
|
+
|
|
37
|
+
const APIS: Record<BuiltinPluginId, PluginApi> = {
|
|
38
|
+
'workflow-runner': workflowApi,
|
|
39
|
+
'cron-runner': cronApi,
|
|
40
|
+
computer_use: computerUseApi,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
for (const id of BUILTIN_PLUGIN_IDS) setBuiltinPluginApi(id, APIS[id]);
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { readFile, readdir } from 'node:fs/promises';
|
|
2
|
-
import { join } from 'node:path';
|
|
2
|
+
import { join, resolve } from 'node:path';
|
|
3
|
+
import { getWorkingDir } from '../bootstrap/workingDir.js';
|
|
3
4
|
import { getResourceSearchPaths } from '../utils/resourcePaths.js';
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
import { readPluginManifest } from './pluginManifest.js';
|
|
6
|
+
const pluginCaches = new Map();
|
|
7
|
+
function cacheFor(workingDir = getWorkingDir()) {
|
|
8
|
+
return pluginCaches.get(resolve(workingDir)) ?? new Map();
|
|
9
|
+
}
|
|
6
10
|
function stripQuotes(s) {
|
|
7
11
|
const trimmed = s.trim();
|
|
8
12
|
if ((trimmed.startsWith('"') && trimmed.endsWith('"')) ||
|
|
@@ -38,23 +42,22 @@ function parseMarkdownFrontmatter(content) {
|
|
|
38
42
|
}
|
|
39
43
|
async function loadPlugin(pluginDirPath) {
|
|
40
44
|
const dirName = baseName(pluginDirPath);
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
manifestName
|
|
49
|
-
manifestVersion = parsed.version;
|
|
50
|
-
manifestDesc = parsed.description;
|
|
51
|
-
}
|
|
52
|
-
catch {
|
|
45
|
+
// manifest 只在 `pluginManifest.ts` 解析一处:字段一旦有两份读法就会漂移,
|
|
46
|
+
// 而说明书发现(vision/appGuide.ts)读的正是同一个文件。
|
|
47
|
+
const manifest = readPluginManifest(pluginDirPath);
|
|
48
|
+
const manifestName = manifest?.name ?? dirName;
|
|
49
|
+
const manifestVersion = manifest?.version;
|
|
50
|
+
const manifestDesc = manifest?.description;
|
|
51
|
+
for (const issue of manifest?.issues ?? []) {
|
|
52
|
+
console.warn(`[minimal-agent] 插件 "${manifestName}" 的 plugin.json:${issue}`);
|
|
53
53
|
}
|
|
54
54
|
const commandsDir = join(pluginDirPath, 'commands');
|
|
55
55
|
const commands = [];
|
|
56
56
|
try {
|
|
57
57
|
const entries = await readdir(commandsDir, { withFileTypes: true });
|
|
58
|
+
// 排序理由同 skillList.ts:命令顺序会进系统提示词(formatPluginHint),
|
|
59
|
+
// readdir 的 fs 顺序不稳定会让提示词前缀漂移、打散 provider 的自动前缀缓存。
|
|
60
|
+
entries.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
|
|
58
61
|
for (const entry of entries) {
|
|
59
62
|
if (!entry.name.endsWith('.md'))
|
|
60
63
|
continue;
|
|
@@ -91,7 +94,10 @@ async function loadPlugin(pluginDirPath) {
|
|
|
91
94
|
}
|
|
92
95
|
catch {
|
|
93
96
|
}
|
|
94
|
-
|
|
97
|
+
// 「只提供应用说明书、没有命令也没有 hook」也是合法插件 —— 知识本身就是
|
|
98
|
+
// 一种贡献。此前这里会把它判成「不是插件」直接丢掉。
|
|
99
|
+
const appManualDirs = manifest?.appManualDirs ?? [];
|
|
100
|
+
if (commands.length === 0 && !hasStopHook && appManualDirs.length === 0)
|
|
95
101
|
return null;
|
|
96
102
|
return {
|
|
97
103
|
name: manifestName,
|
|
@@ -100,22 +106,30 @@ async function loadPlugin(pluginDirPath) {
|
|
|
100
106
|
root: pluginDirPath,
|
|
101
107
|
commands,
|
|
102
108
|
hasStopHook,
|
|
109
|
+
appManualDirs,
|
|
103
110
|
};
|
|
104
111
|
}
|
|
105
|
-
export async function discoverPlugins() {
|
|
106
|
-
|
|
107
|
-
|
|
112
|
+
export async function discoverPlugins(workingDir = getWorkingDir()) {
|
|
113
|
+
const cacheKey = resolve(workingDir);
|
|
114
|
+
const cached = pluginCaches.get(cacheKey);
|
|
115
|
+
if (cached) {
|
|
116
|
+
return Array.from(cached.values());
|
|
108
117
|
}
|
|
109
|
-
pluginCache
|
|
110
|
-
discoveryDone = true;
|
|
118
|
+
const pluginCache = new Map();
|
|
111
119
|
// 双源扫描:cwd 优先 + packageRoot fallback;按数组顺序处理,已有 manifestName 跳过
|
|
112
|
-
const searchPaths = getResourceSearchPaths('plugins', import.meta.url);
|
|
120
|
+
const searchPaths = getResourceSearchPaths('plugins', import.meta.url, cacheKey);
|
|
113
121
|
// 命令名 → 首个声明它的插件名。resolveCommand 按插入顺序返回第一个命中,
|
|
114
122
|
// 所以两个不同插件声明同名命令时,先注册者生效、后者被影 —— 不再静默,warn 一次。
|
|
115
123
|
const commandOwners = new Map();
|
|
116
124
|
for (const root of searchPaths) {
|
|
117
125
|
try {
|
|
118
126
|
const entries = await readdir(root, { withFileTypes: true });
|
|
127
|
+
// 排序有两个作用:
|
|
128
|
+
// 1. 提示词缓存:插件清单进系统提示词,顺序必须逐字节可复现(同 skillList.ts)。
|
|
129
|
+
// 2. 顺带修掉一个既有的不确定性 —— 下面「先注册者赢」的命令名冲突裁决此前
|
|
130
|
+
// 取决于 readdir 的 fs 返回顺序,同一份插件目录在不同机器/不同增删历史下
|
|
131
|
+
// 可能裁出不同赢家。排序后裁决稳定为字典序,行为可预测、可写进测试。
|
|
132
|
+
entries.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
|
|
119
133
|
for (const entry of entries) {
|
|
120
134
|
if (!entry.isDirectory())
|
|
121
135
|
continue;
|
|
@@ -142,12 +156,12 @@ export async function discoverPlugins() {
|
|
|
142
156
|
catch {
|
|
143
157
|
}
|
|
144
158
|
}
|
|
159
|
+
pluginCaches.set(cacheKey, pluginCache);
|
|
145
160
|
return Array.from(pluginCache.values());
|
|
146
161
|
}
|
|
147
162
|
/** 仅供测试:重置 discovery cache。 */
|
|
148
163
|
export function _resetPluginCache() {
|
|
149
|
-
|
|
150
|
-
discoveryDone = false;
|
|
164
|
+
pluginCaches.clear();
|
|
151
165
|
}
|
|
152
166
|
export function resolveCommand(input) {
|
|
153
167
|
const trimmed = input.trimStart();
|
|
@@ -156,7 +170,7 @@ export function resolveCommand(input) {
|
|
|
156
170
|
const spaceIdx = trimmed.indexOf(' ', 1);
|
|
157
171
|
const cmdName = spaceIdx >= 0 ? trimmed.slice(1, spaceIdx) : trimmed.slice(1);
|
|
158
172
|
const args = spaceIdx >= 0 ? trimmed.slice(spaceIdx + 1) : '';
|
|
159
|
-
for (const plugin of
|
|
173
|
+
for (const plugin of cacheFor().values()) {
|
|
160
174
|
for (const cmd of plugin.commands) {
|
|
161
175
|
if (cmd.name === cmdName) {
|
|
162
176
|
return { cmd, arguments: args };
|
|
@@ -183,7 +197,7 @@ export function buildCommandInput(resolved) {
|
|
|
183
197
|
// src 内无调用不代表死代码,勿删。
|
|
184
198
|
export function listAvailableCommands() {
|
|
185
199
|
const result = [];
|
|
186
|
-
for (const plugin of
|
|
200
|
+
for (const plugin of cacheFor().values()) {
|
|
187
201
|
for (const cmd of plugin.commands) {
|
|
188
202
|
result.push({
|
|
189
203
|
command: `/${cmd.name}`,
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { readFile, readdir } from 'node:fs/promises';
|
|
2
|
+
import { join, resolve } from 'node:path';
|
|
3
|
+
|
|
4
|
+
import { getWorkingDir } from '../bootstrap/workingDir.js';
|
|
5
|
+
import { getResourceSearchPaths } from '../utils/resourcePaths.js';
|
|
6
|
+
import { readPluginManifest } from './pluginManifest.js';
|
|
7
|
+
|
|
8
|
+
export interface PluginCommand {
|
|
9
|
+
name: string;
|
|
10
|
+
description: string;
|
|
11
|
+
argumentHint?: string;
|
|
12
|
+
pluginName: string;
|
|
13
|
+
pluginRoot: string;
|
|
14
|
+
promptBody: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface PluginManifest {
|
|
18
|
+
name: string;
|
|
19
|
+
version?: string;
|
|
20
|
+
description?: string;
|
|
21
|
+
root: string;
|
|
22
|
+
commands: PluginCommand[];
|
|
23
|
+
hasStopHook: boolean;
|
|
24
|
+
/** manifest 里 `appManuals` 声明的应用说明书目录(绝对路径,已安全收敛)。 */
|
|
25
|
+
appManualDirs: string[];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const pluginCaches = new Map<string, Map<string, PluginManifest>>();
|
|
29
|
+
|
|
30
|
+
function cacheFor(workingDir = getWorkingDir()): Map<string, PluginManifest> {
|
|
31
|
+
return pluginCaches.get(resolve(workingDir)) ?? new Map<string, PluginManifest>();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function stripQuotes(s: string): string {
|
|
35
|
+
const trimmed = s.trim();
|
|
36
|
+
if (
|
|
37
|
+
(trimmed.startsWith('"') && trimmed.endsWith('"')) ||
|
|
38
|
+
(trimmed.startsWith("'") && trimmed.endsWith("'"))
|
|
39
|
+
) {
|
|
40
|
+
return trimmed.slice(1, -1);
|
|
41
|
+
}
|
|
42
|
+
return trimmed;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 跨平台取路径最后一段。Windows 上 join() 产出反斜杠路径,单纯 split('/')
|
|
47
|
+
* 不切分会让整条绝对路径变成"目录名"。同时吃 \\ 与 /,与
|
|
48
|
+
* hookEngine.pluginNameFromRoot 的归一逻辑保持一致。
|
|
49
|
+
*/
|
|
50
|
+
export function baseName(p: string): string {
|
|
51
|
+
const parts = p.replace(/[\\/]+$/, '').split(/[\\/]/);
|
|
52
|
+
return parts[parts.length - 1] || p;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function parseMarkdownFrontmatter(content: string): Record<string, string> {
|
|
56
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
57
|
+
if (!match) return {};
|
|
58
|
+
|
|
59
|
+
const frontmatter: Record<string, string> = {};
|
|
60
|
+
for (const line of match[1].split('\n')) {
|
|
61
|
+
const colon = line.indexOf(':');
|
|
62
|
+
if (colon < 0) continue;
|
|
63
|
+
const key = line.slice(0, colon).trim();
|
|
64
|
+
const value = line.slice(colon + 1).trim();
|
|
65
|
+
if (key) frontmatter[key] = stripQuotes(value);
|
|
66
|
+
}
|
|
67
|
+
return frontmatter;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function loadPlugin(pluginDirPath: string): Promise<PluginManifest | null> {
|
|
71
|
+
const dirName = baseName(pluginDirPath);
|
|
72
|
+
|
|
73
|
+
// manifest 只在 `pluginManifest.ts` 解析一处:字段一旦有两份读法就会漂移,
|
|
74
|
+
// 而说明书发现(vision/appGuide.ts)读的正是同一个文件。
|
|
75
|
+
const manifest = readPluginManifest(pluginDirPath);
|
|
76
|
+
const manifestName = manifest?.name ?? dirName;
|
|
77
|
+
const manifestVersion = manifest?.version;
|
|
78
|
+
const manifestDesc = manifest?.description;
|
|
79
|
+
for (const issue of manifest?.issues ?? []) {
|
|
80
|
+
console.warn(`[minimal-agent] 插件 "${manifestName}" 的 plugin.json:${issue}`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const commandsDir = join(pluginDirPath, 'commands');
|
|
84
|
+
const commands: PluginCommand[] = [];
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const entries = await readdir(commandsDir, { withFileTypes: true });
|
|
88
|
+
// 排序理由同 skillList.ts:命令顺序会进系统提示词(formatPluginHint),
|
|
89
|
+
// readdir 的 fs 顺序不稳定会让提示词前缀漂移、打散 provider 的自动前缀缓存。
|
|
90
|
+
entries.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
|
|
91
|
+
for (const entry of entries) {
|
|
92
|
+
if (!entry.name.endsWith('.md')) continue;
|
|
93
|
+
|
|
94
|
+
const cmdPath = join(commandsDir, entry.name);
|
|
95
|
+
try {
|
|
96
|
+
const content = await readFile(cmdPath, 'utf8');
|
|
97
|
+
const fm = parseMarkdownFrontmatter(content);
|
|
98
|
+
|
|
99
|
+
const sep = content.indexOf('\n---', 4);
|
|
100
|
+
const body = sep >= 0 ? content.slice(sep + 4).trim() : content.trim();
|
|
101
|
+
|
|
102
|
+
commands.push({
|
|
103
|
+
name: entry.name.replace(/\.md$/, ''),
|
|
104
|
+
description: fm.description ?? '(no description)',
|
|
105
|
+
argumentHint: fm['argument-hint'],
|
|
106
|
+
pluginName: manifestName,
|
|
107
|
+
pluginRoot: pluginDirPath,
|
|
108
|
+
promptBody: body,
|
|
109
|
+
});
|
|
110
|
+
} catch {
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
} catch {
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const hooksJsonPath = join(pluginDirPath, 'hooks', 'hooks.json');
|
|
117
|
+
let hasStopHook = false;
|
|
118
|
+
try {
|
|
119
|
+
const hooksRaw = await readFile(hooksJsonPath, 'utf8');
|
|
120
|
+
const hooksParsed = JSON.parse(hooksRaw);
|
|
121
|
+
const stopHooks = hooksParsed?.hooks?.Stop;
|
|
122
|
+
if (Array.isArray(stopHooks) && stopHooks.length > 0) {
|
|
123
|
+
hasStopHook = true;
|
|
124
|
+
}
|
|
125
|
+
} catch {
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// 「只提供应用说明书、没有命令也没有 hook」也是合法插件 —— 知识本身就是
|
|
129
|
+
// 一种贡献。此前这里会把它判成「不是插件」直接丢掉。
|
|
130
|
+
const appManualDirs = manifest?.appManualDirs ?? [];
|
|
131
|
+
if (commands.length === 0 && !hasStopHook && appManualDirs.length === 0) return null;
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
name: manifestName,
|
|
135
|
+
version: manifestVersion,
|
|
136
|
+
description: manifestDesc,
|
|
137
|
+
root: pluginDirPath,
|
|
138
|
+
commands,
|
|
139
|
+
hasStopHook,
|
|
140
|
+
appManualDirs,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export async function discoverPlugins(workingDir = getWorkingDir()): Promise<PluginManifest[]> {
|
|
145
|
+
const cacheKey = resolve(workingDir);
|
|
146
|
+
const cached = pluginCaches.get(cacheKey);
|
|
147
|
+
if (cached) {
|
|
148
|
+
return Array.from(cached.values());
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const pluginCache = new Map<string, PluginManifest>();
|
|
152
|
+
|
|
153
|
+
// 双源扫描:cwd 优先 + packageRoot fallback;按数组顺序处理,已有 manifestName 跳过
|
|
154
|
+
const searchPaths = getResourceSearchPaths('plugins', import.meta.url, cacheKey);
|
|
155
|
+
|
|
156
|
+
// 命令名 → 首个声明它的插件名。resolveCommand 按插入顺序返回第一个命中,
|
|
157
|
+
// 所以两个不同插件声明同名命令时,先注册者生效、后者被影 —— 不再静默,warn 一次。
|
|
158
|
+
const commandOwners = new Map<string, string>();
|
|
159
|
+
|
|
160
|
+
for (const root of searchPaths) {
|
|
161
|
+
try {
|
|
162
|
+
const entries = await readdir(root, { withFileTypes: true });
|
|
163
|
+
// 排序有两个作用:
|
|
164
|
+
// 1. 提示词缓存:插件清单进系统提示词,顺序必须逐字节可复现(同 skillList.ts)。
|
|
165
|
+
// 2. 顺带修掉一个既有的不确定性 —— 下面「先注册者赢」的命令名冲突裁决此前
|
|
166
|
+
// 取决于 readdir 的 fs 返回顺序,同一份插件目录在不同机器/不同增删历史下
|
|
167
|
+
// 可能裁出不同赢家。排序后裁决稳定为字典序,行为可预测、可写进测试。
|
|
168
|
+
entries.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
|
|
169
|
+
|
|
170
|
+
for (const entry of entries) {
|
|
171
|
+
if (!entry.isDirectory()) continue;
|
|
172
|
+
if (entry.name.startsWith('.')) continue;
|
|
173
|
+
|
|
174
|
+
const plugin = await loadPlugin(join(root, entry.name));
|
|
175
|
+
if (!plugin) continue;
|
|
176
|
+
if (pluginCache.has(plugin.name)) continue; // cwd 已注册的 manifestName,packageRoot 同名跳过
|
|
177
|
+
pluginCache.set(plugin.name, plugin);
|
|
178
|
+
|
|
179
|
+
for (const cmd of plugin.commands) {
|
|
180
|
+
const owner = commandOwners.get(cmd.name);
|
|
181
|
+
if (owner && owner !== plugin.name) {
|
|
182
|
+
console.warn(
|
|
183
|
+
`[minimal-agent] 命令名冲突:/${cmd.name} 同时由插件 "${owner}" 与 "${plugin.name}" 声明;` +
|
|
184
|
+
`先注册的 "${owner}" 生效,"${plugin.name}" 的同名命令被忽略。`,
|
|
185
|
+
);
|
|
186
|
+
} else if (!owner) {
|
|
187
|
+
commandOwners.set(cmd.name, plugin.name);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
} catch {
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
pluginCaches.set(cacheKey, pluginCache);
|
|
196
|
+
return Array.from(pluginCache.values());
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** 仅供测试:重置 discovery cache。 */
|
|
200
|
+
export function _resetPluginCache(): void {
|
|
201
|
+
pluginCaches.clear();
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export function resolveCommand(input: string): { cmd: PluginCommand; arguments: string } | null {
|
|
205
|
+
const trimmed = input.trimStart();
|
|
206
|
+
if (!trimmed.startsWith('/')) return null;
|
|
207
|
+
|
|
208
|
+
const spaceIdx = trimmed.indexOf(' ', 1);
|
|
209
|
+
const cmdName = spaceIdx >= 0 ? trimmed.slice(1, spaceIdx) : trimmed.slice(1);
|
|
210
|
+
const args = spaceIdx >= 0 ? trimmed.slice(spaceIdx + 1) : '';
|
|
211
|
+
|
|
212
|
+
for (const plugin of cacheFor().values()) {
|
|
213
|
+
for (const cmd of plugin.commands) {
|
|
214
|
+
if (cmd.name === cmdName) {
|
|
215
|
+
return { cmd, arguments: args };
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export function buildCommandInput(
|
|
224
|
+
resolved: { cmd: PluginCommand; arguments: string },
|
|
225
|
+
): string {
|
|
226
|
+
const { cmd, arguments: args } = resolved;
|
|
227
|
+
|
|
228
|
+
let input = cmd.promptBody;
|
|
229
|
+
|
|
230
|
+
input = input.replaceAll('${CLAUDE_PLUGIN_ROOT}', cmd.pluginRoot);
|
|
231
|
+
|
|
232
|
+
// 模板是否自己引用了参数占位符。引用了就别再补尾注,否则参数出现两遍。
|
|
233
|
+
const hadArgsPlaceholder =
|
|
234
|
+
input.includes('$ARGUMENTS') || input.includes('${ARGUMENTS}');
|
|
235
|
+
|
|
236
|
+
input = input.replaceAll('$ARGUMENTS', args);
|
|
237
|
+
input = input.replaceAll('${ARGUMENTS}', args);
|
|
238
|
+
|
|
239
|
+
if (!hadArgsPlaceholder && args.trim()) {
|
|
240
|
+
input += `\n\n用户参数: ${args.trim()}`;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return input;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// 消费方是测试与宿主侧枚举(V1 红线守护测试 pluginRunner.isolation.test.ts 用它
|
|
247
|
+
// 断言「非 / 输入零 discovery 副作用」;commandRouter.test.ts 断言命令清单)——
|
|
248
|
+
// src 内无调用不代表死代码,勿删。
|
|
249
|
+
export function listAvailableCommands(): { command: string; plugin: string; description: string }[] {
|
|
250
|
+
const result: { command: string; plugin: string; description: string }[] = [];
|
|
251
|
+
for (const plugin of cacheFor().values()) {
|
|
252
|
+
for (const cmd of plugin.commands) {
|
|
253
|
+
result.push({
|
|
254
|
+
command: `/${cmd.name}`,
|
|
255
|
+
plugin: plugin.name,
|
|
256
|
+
description: cmd.description,
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return result;
|
|
261
|
+
}
|