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,149 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { mkdir, open, readFile, readdir, rename, rm, stat, } from 'node:fs/promises';
|
|
3
|
+
import { dirname, join, resolve } from 'node:path';
|
|
4
|
+
import { agentStateDir } from '../context/agentHome.js';
|
|
5
|
+
function segment(value, fallback) {
|
|
6
|
+
return ((value ?? fallback).replace(/[^a-zA-Z0-9._-]/g, '_').slice(0, 120) ||
|
|
7
|
+
fallback);
|
|
8
|
+
}
|
|
9
|
+
export function sessionRuntimeDir(identity) {
|
|
10
|
+
return join(agentStateDir(), 'runtime', segment(identity.workspaceId, 'local'), segment(identity.sessionId, 'local'));
|
|
11
|
+
}
|
|
12
|
+
const queues = new Map();
|
|
13
|
+
export async function withRuntimeFileLock(path, work) {
|
|
14
|
+
const key = resolve(path);
|
|
15
|
+
const previous = queues.get(key) ?? Promise.resolve();
|
|
16
|
+
let release;
|
|
17
|
+
const current = new Promise((done) => {
|
|
18
|
+
release = done;
|
|
19
|
+
});
|
|
20
|
+
const tail = previous.then(() => current);
|
|
21
|
+
queues.set(key, tail);
|
|
22
|
+
await previous.catch(() => undefined);
|
|
23
|
+
let lockHandle;
|
|
24
|
+
const lockPath = `${path}.lock`;
|
|
25
|
+
await mkdir(dirname(path), { recursive: true, mode: 0o700 });
|
|
26
|
+
try {
|
|
27
|
+
const deadline = Date.now() + 10_000;
|
|
28
|
+
while (!lockHandle) {
|
|
29
|
+
try {
|
|
30
|
+
lockHandle = await open(lockPath, 'wx', 0o600);
|
|
31
|
+
await lockHandle.writeFile(`${process.pid}\n${Date.now()}\n`);
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
if (error.code !== 'EEXIST')
|
|
35
|
+
throw error;
|
|
36
|
+
const age = Date.now() -
|
|
37
|
+
(await stat(lockPath).catch(() => ({ mtimeMs: Date.now() }))).mtimeMs;
|
|
38
|
+
if (age > 30_000)
|
|
39
|
+
await rm(lockPath, { force: true });
|
|
40
|
+
else if (Date.now() >= deadline)
|
|
41
|
+
throw new Error(`runtime lock timeout: ${path}`);
|
|
42
|
+
else
|
|
43
|
+
await new Promise((r) => setTimeout(r, 25));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return await work();
|
|
47
|
+
}
|
|
48
|
+
finally {
|
|
49
|
+
await lockHandle?.close().catch(() => undefined);
|
|
50
|
+
if (lockHandle)
|
|
51
|
+
await rm(lockPath, { force: true }).catch(() => undefined);
|
|
52
|
+
release();
|
|
53
|
+
if (queues.get(key) === tail)
|
|
54
|
+
queues.delete(key);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
export async function readRuntimeJson(path, fallback) {
|
|
58
|
+
try {
|
|
59
|
+
return JSON.parse(await readFile(path, 'utf8'));
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return fallback;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export async function writeRuntimeJson(path, value) {
|
|
66
|
+
await mkdir(dirname(path), { recursive: true, mode: 0o700 });
|
|
67
|
+
const temp = `${path}.${randomUUID()}.tmp`;
|
|
68
|
+
try {
|
|
69
|
+
const handle = await open(temp, 'wx', 0o600);
|
|
70
|
+
try {
|
|
71
|
+
await handle.writeFile(`${JSON.stringify(value, null, 2)}\n`, 'utf8');
|
|
72
|
+
await handle.sync();
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
await handle.close();
|
|
76
|
+
}
|
|
77
|
+
await rename(temp, path);
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
await rm(temp, { force: true }).catch(() => undefined);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
export async function mutateRuntimeJson(path, fallback, mutate) {
|
|
84
|
+
return withRuntimeFileLock(path, async () => {
|
|
85
|
+
const next = await mutate(await readRuntimeJson(path, fallback));
|
|
86
|
+
await writeRuntimeJson(path, next);
|
|
87
|
+
return next;
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
export async function removeManagedPath(path, expectedRoot) {
|
|
91
|
+
const target = resolve(path);
|
|
92
|
+
const root = resolve(expectedRoot);
|
|
93
|
+
const rel = target.slice(root.length);
|
|
94
|
+
if (target === root || !target.startsWith(`${root}/`) || rel.includes('\0')) {
|
|
95
|
+
throw new Error(`拒绝清理托管根目录之外的路径:${target}`);
|
|
96
|
+
}
|
|
97
|
+
await rm(target, { recursive: true, force: true });
|
|
98
|
+
}
|
|
99
|
+
export async function runtimeFileVersion(path) {
|
|
100
|
+
const info = await stat(path);
|
|
101
|
+
return `${info.dev}:${info.ino}:${info.size}:${info.mtimeMs}`;
|
|
102
|
+
}
|
|
103
|
+
const activeOutputs = new Set();
|
|
104
|
+
const OUTPUT_RETENTION_MS = 7 * 24 * 60 * 60_000;
|
|
105
|
+
const OUTPUT_GLOBAL_LIMIT = 5 * 1024 * 1024 * 1024;
|
|
106
|
+
let pruneOutputsPromise;
|
|
107
|
+
export function registerRuntimeOutput(path) {
|
|
108
|
+
activeOutputs.add(resolve(path));
|
|
109
|
+
}
|
|
110
|
+
export function unregisterRuntimeOutput(path) {
|
|
111
|
+
activeOutputs.delete(resolve(path));
|
|
112
|
+
}
|
|
113
|
+
export function pruneRuntimeOutputs() {
|
|
114
|
+
pruneOutputsPromise ??= (async () => {
|
|
115
|
+
const root = join(agentStateDir(), 'runtime');
|
|
116
|
+
const files = [];
|
|
117
|
+
for (const workspace of await readdir(root).catch(() => [])) {
|
|
118
|
+
const workspaceDir = join(root, workspace);
|
|
119
|
+
for (const session of await readdir(workspaceDir).catch(() => [])) {
|
|
120
|
+
const outputDir = join(workspaceDir, session, 'outputs');
|
|
121
|
+
const sessionFiles = [];
|
|
122
|
+
for (const name of await readdir(outputDir).catch(() => [])) {
|
|
123
|
+
const path = join(outputDir, name);
|
|
124
|
+
const info = await stat(path).catch(() => undefined);
|
|
125
|
+
if (info?.isFile() && !activeOutputs.has(resolve(path))) {
|
|
126
|
+
sessionFiles.push({ path, size: info.size, mtimeMs: info.mtimeMs });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
sessionFiles.sort((left, right) => right.mtimeMs - left.mtimeMs);
|
|
130
|
+
await Promise.all(sessionFiles
|
|
131
|
+
.slice(50)
|
|
132
|
+
.map((file) => rm(file.path, { force: true }).catch(() => undefined)));
|
|
133
|
+
files.push(...sessionFiles.slice(0, 50));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
files.sort((left, right) => right.mtimeMs - left.mtimeMs);
|
|
137
|
+
let retainedBytes = 0;
|
|
138
|
+
const cutoff = Date.now() - OUTPUT_RETENTION_MS;
|
|
139
|
+
for (const file of files) {
|
|
140
|
+
retainedBytes += file.size;
|
|
141
|
+
if (file.mtimeMs < cutoff || retainedBytes > OUTPUT_GLOBAL_LIMIT) {
|
|
142
|
+
await rm(file.path, { force: true }).catch(() => undefined);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
})().finally(() => {
|
|
146
|
+
pruneOutputsPromise = undefined;
|
|
147
|
+
});
|
|
148
|
+
return pruneOutputsPromise;
|
|
149
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import {
|
|
3
|
+
mkdir,
|
|
4
|
+
open,
|
|
5
|
+
readFile,
|
|
6
|
+
readdir,
|
|
7
|
+
rename,
|
|
8
|
+
rm,
|
|
9
|
+
stat,
|
|
10
|
+
} from 'node:fs/promises';
|
|
11
|
+
import { dirname, join, resolve } from 'node:path';
|
|
12
|
+
|
|
13
|
+
import { agentStateDir } from '../context/agentHome.js';
|
|
14
|
+
|
|
15
|
+
export interface RuntimeIdentity {
|
|
16
|
+
workspaceId?: string;
|
|
17
|
+
sessionId?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function segment(value: string | undefined, fallback: string): string {
|
|
21
|
+
return (
|
|
22
|
+
(value ?? fallback).replace(/[^a-zA-Z0-9._-]/g, '_').slice(0, 120) ||
|
|
23
|
+
fallback
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function sessionRuntimeDir(identity: RuntimeIdentity): string {
|
|
28
|
+
return join(
|
|
29
|
+
agentStateDir(),
|
|
30
|
+
'runtime',
|
|
31
|
+
segment(identity.workspaceId, 'local'),
|
|
32
|
+
segment(identity.sessionId, 'local'),
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const queues = new Map<string, Promise<unknown>>();
|
|
37
|
+
export async function withRuntimeFileLock<T>(
|
|
38
|
+
path: string,
|
|
39
|
+
work: () => Promise<T>,
|
|
40
|
+
): Promise<T> {
|
|
41
|
+
const key = resolve(path);
|
|
42
|
+
const previous = queues.get(key) ?? Promise.resolve();
|
|
43
|
+
let release!: () => void;
|
|
44
|
+
const current = new Promise<void>((done) => {
|
|
45
|
+
release = done;
|
|
46
|
+
});
|
|
47
|
+
const tail = previous.then(() => current);
|
|
48
|
+
queues.set(key, tail);
|
|
49
|
+
await previous.catch(() => undefined);
|
|
50
|
+
let lockHandle: Awaited<ReturnType<typeof open>> | undefined;
|
|
51
|
+
const lockPath = `${path}.lock`;
|
|
52
|
+
await mkdir(dirname(path), { recursive: true, mode: 0o700 });
|
|
53
|
+
try {
|
|
54
|
+
const deadline = Date.now() + 10_000;
|
|
55
|
+
while (!lockHandle) {
|
|
56
|
+
try {
|
|
57
|
+
lockHandle = await open(lockPath, 'wx', 0o600);
|
|
58
|
+
await lockHandle.writeFile(`${process.pid}\n${Date.now()}\n`);
|
|
59
|
+
} catch (error) {
|
|
60
|
+
if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error;
|
|
61
|
+
const age =
|
|
62
|
+
Date.now() -
|
|
63
|
+
(await stat(lockPath).catch(() => ({ mtimeMs: Date.now() }))).mtimeMs;
|
|
64
|
+
if (age > 30_000) await rm(lockPath, { force: true });
|
|
65
|
+
else if (Date.now() >= deadline)
|
|
66
|
+
throw new Error(`runtime lock timeout: ${path}`);
|
|
67
|
+
else await new Promise((r) => setTimeout(r, 25));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return await work();
|
|
71
|
+
} finally {
|
|
72
|
+
await lockHandle?.close().catch(() => undefined);
|
|
73
|
+
if (lockHandle) await rm(lockPath, { force: true }).catch(() => undefined);
|
|
74
|
+
release();
|
|
75
|
+
if (queues.get(key) === tail) queues.delete(key);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export async function readRuntimeJson<T>(
|
|
80
|
+
path: string,
|
|
81
|
+
fallback: T,
|
|
82
|
+
): Promise<T> {
|
|
83
|
+
try {
|
|
84
|
+
return JSON.parse(await readFile(path, 'utf8')) as T;
|
|
85
|
+
} catch {
|
|
86
|
+
return fallback;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export async function writeRuntimeJson(
|
|
91
|
+
path: string,
|
|
92
|
+
value: unknown,
|
|
93
|
+
): Promise<void> {
|
|
94
|
+
await mkdir(dirname(path), { recursive: true, mode: 0o700 });
|
|
95
|
+
const temp = `${path}.${randomUUID()}.tmp`;
|
|
96
|
+
try {
|
|
97
|
+
const handle = await open(temp, 'wx', 0o600);
|
|
98
|
+
try {
|
|
99
|
+
await handle.writeFile(`${JSON.stringify(value, null, 2)}\n`, 'utf8');
|
|
100
|
+
await handle.sync();
|
|
101
|
+
} finally {
|
|
102
|
+
await handle.close();
|
|
103
|
+
}
|
|
104
|
+
await rename(temp, path);
|
|
105
|
+
} finally {
|
|
106
|
+
await rm(temp, { force: true }).catch(() => undefined);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export async function mutateRuntimeJson<T>(
|
|
111
|
+
path: string,
|
|
112
|
+
fallback: T,
|
|
113
|
+
mutate: (value: T) => T | Promise<T>,
|
|
114
|
+
): Promise<T> {
|
|
115
|
+
return withRuntimeFileLock(path, async () => {
|
|
116
|
+
const next = await mutate(await readRuntimeJson(path, fallback));
|
|
117
|
+
await writeRuntimeJson(path, next);
|
|
118
|
+
return next;
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export async function removeManagedPath(
|
|
123
|
+
path: string,
|
|
124
|
+
expectedRoot: string,
|
|
125
|
+
): Promise<void> {
|
|
126
|
+
const target = resolve(path);
|
|
127
|
+
const root = resolve(expectedRoot);
|
|
128
|
+
const rel = target.slice(root.length);
|
|
129
|
+
if (target === root || !target.startsWith(`${root}/`) || rel.includes('\0')) {
|
|
130
|
+
throw new Error(`拒绝清理托管根目录之外的路径:${target}`);
|
|
131
|
+
}
|
|
132
|
+
await rm(target, { recursive: true, force: true });
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export async function runtimeFileVersion(path: string): Promise<string> {
|
|
136
|
+
const info = await stat(path);
|
|
137
|
+
return `${info.dev}:${info.ino}:${info.size}:${info.mtimeMs}`;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const activeOutputs = new Set<string>();
|
|
141
|
+
const OUTPUT_RETENTION_MS = 7 * 24 * 60 * 60_000;
|
|
142
|
+
const OUTPUT_GLOBAL_LIMIT = 5 * 1024 * 1024 * 1024;
|
|
143
|
+
let pruneOutputsPromise: Promise<void> | undefined;
|
|
144
|
+
|
|
145
|
+
export function registerRuntimeOutput(path: string): void {
|
|
146
|
+
activeOutputs.add(resolve(path));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function unregisterRuntimeOutput(path: string): void {
|
|
150
|
+
activeOutputs.delete(resolve(path));
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function pruneRuntimeOutputs(): Promise<void> {
|
|
154
|
+
pruneOutputsPromise ??= (async () => {
|
|
155
|
+
const root = join(agentStateDir(), 'runtime');
|
|
156
|
+
const files: Array<{ path: string; size: number; mtimeMs: number }> = [];
|
|
157
|
+
for (const workspace of await readdir(root).catch(() => [])) {
|
|
158
|
+
const workspaceDir = join(root, workspace);
|
|
159
|
+
for (const session of await readdir(workspaceDir).catch(() => [])) {
|
|
160
|
+
const outputDir = join(workspaceDir, session, 'outputs');
|
|
161
|
+
const sessionFiles: Array<{
|
|
162
|
+
path: string;
|
|
163
|
+
size: number;
|
|
164
|
+
mtimeMs: number;
|
|
165
|
+
}> = [];
|
|
166
|
+
for (const name of await readdir(outputDir).catch(() => [])) {
|
|
167
|
+
const path = join(outputDir, name);
|
|
168
|
+
const info = await stat(path).catch(() => undefined);
|
|
169
|
+
if (info?.isFile() && !activeOutputs.has(resolve(path))) {
|
|
170
|
+
sessionFiles.push({ path, size: info.size, mtimeMs: info.mtimeMs });
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
sessionFiles.sort((left, right) => right.mtimeMs - left.mtimeMs);
|
|
174
|
+
await Promise.all(
|
|
175
|
+
sessionFiles
|
|
176
|
+
.slice(50)
|
|
177
|
+
.map((file) =>
|
|
178
|
+
rm(file.path, { force: true }).catch(() => undefined),
|
|
179
|
+
),
|
|
180
|
+
);
|
|
181
|
+
files.push(...sessionFiles.slice(0, 50));
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
files.sort((left, right) => right.mtimeMs - left.mtimeMs);
|
|
185
|
+
let retainedBytes = 0;
|
|
186
|
+
const cutoff = Date.now() - OUTPUT_RETENTION_MS;
|
|
187
|
+
for (const file of files) {
|
|
188
|
+
retainedBytes += file.size;
|
|
189
|
+
if (file.mtimeMs < cutoff || retainedBytes > OUTPUT_GLOBAL_LIMIT) {
|
|
190
|
+
await rm(file.path, { force: true }).catch(() => undefined);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
})().finally(() => {
|
|
194
|
+
pruneOutputsPromise = undefined;
|
|
195
|
+
});
|
|
196
|
+
return pruneOutputsPromise;
|
|
197
|
+
}
|
|
@@ -4,16 +4,92 @@
|
|
|
4
4
|
* ------------------------------------------------------------
|
|
5
5
|
* 把 reactiveCompact + microCompactLite 的可注入状态打包。
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* 让每个 chatId 的工具结果去重缓存、反应式自救标记互不串扰。
|
|
7
|
+
* 长生命周期宿主按 workspace + session 复用一份;一次性 CLI 可直接创建。
|
|
8
|
+
* 让每个 chatId 的工具结果去重缓存、文件读取证据和后台任务互不串扰。
|
|
10
9
|
* ============================================================
|
|
11
10
|
*/
|
|
12
11
|
import { createMicroCompactState, } from '../context/microCompactLite.js';
|
|
13
12
|
import { createReactiveCompactState, } from '../context/reactiveCompact.js';
|
|
13
|
+
import { createFileReadState } from '../tools/shared/fileState.js';
|
|
14
|
+
import { createBackgroundTaskState, disposeBackgroundTaskState, } from '../tools/tasks/backgroundTaskService.js';
|
|
15
|
+
import { createAgentTaskState, stopAllAgentTasks } from '../tools/agent/agentTaskService.js';
|
|
14
16
|
export function createSessionState() {
|
|
15
17
|
return {
|
|
16
18
|
reactive: createReactiveCompactState(),
|
|
17
19
|
microCompact: createMicroCompactState(),
|
|
20
|
+
fileReads: createFileReadState(),
|
|
21
|
+
backgroundTasks: createBackgroundTaskState(),
|
|
22
|
+
agentTasks: createAgentTaskState(),
|
|
18
23
|
};
|
|
19
24
|
}
|
|
25
|
+
const persistentStates = new Map();
|
|
26
|
+
const MAX_PERSISTENT_STATES = 128;
|
|
27
|
+
const MAX_IDLE_MS = 24 * 60 * 60_000;
|
|
28
|
+
/** Collision-free durable key shared by Desktop, CLI and headless hosts. */
|
|
29
|
+
export function sessionStateKey(identity) {
|
|
30
|
+
return JSON.stringify([
|
|
31
|
+
identity.surface,
|
|
32
|
+
identity.workspaceId ?? '',
|
|
33
|
+
identity.cwd ?? '',
|
|
34
|
+
identity.sessionId,
|
|
35
|
+
]);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Return process-local state scoped to a durable host session key. This keeps
|
|
39
|
+
* read evidence and background tasks available across user turns without ever
|
|
40
|
+
* sharing them between workspaces or conversations.
|
|
41
|
+
*/
|
|
42
|
+
export function getOrCreateSessionState(key) {
|
|
43
|
+
const now = Date.now();
|
|
44
|
+
let entry = persistentStates.get(key);
|
|
45
|
+
if (!entry) {
|
|
46
|
+
entry = { state: createSessionState(), lastUsedAt: now };
|
|
47
|
+
persistentStates.set(key, entry);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
entry.lastUsedAt = now;
|
|
51
|
+
}
|
|
52
|
+
prunePersistentStates(now, key);
|
|
53
|
+
return entry.state;
|
|
54
|
+
}
|
|
55
|
+
export async function disposeSessionState(key) {
|
|
56
|
+
const entry = persistentStates.get(key);
|
|
57
|
+
if (!entry)
|
|
58
|
+
return;
|
|
59
|
+
persistentStates.delete(key);
|
|
60
|
+
await disposeBackgroundTaskState(entry.state.backgroundTasks);
|
|
61
|
+
await stopAllAgentTasks(entry.state.agentTasks);
|
|
62
|
+
entry.state.fileReads.entries.clear();
|
|
63
|
+
}
|
|
64
|
+
export async function disposeAllSessionStates() {
|
|
65
|
+
const entries = [...persistentStates.values()];
|
|
66
|
+
persistentStates.clear();
|
|
67
|
+
await Promise.all(entries.map(async ({ state }) => {
|
|
68
|
+
await disposeBackgroundTaskState(state.backgroundTasks);
|
|
69
|
+
await stopAllAgentTasks(state.agentTasks);
|
|
70
|
+
state.fileReads.entries.clear();
|
|
71
|
+
}));
|
|
72
|
+
}
|
|
73
|
+
export async function disposeDetachedSessionState(state) {
|
|
74
|
+
await disposeBackgroundTaskState(state.backgroundTasks);
|
|
75
|
+
await stopAllAgentTasks(state.agentTasks);
|
|
76
|
+
state.fileReads.entries.clear();
|
|
77
|
+
}
|
|
78
|
+
function prunePersistentStates(now, keepKey) {
|
|
79
|
+
const removable = [...persistentStates.entries()]
|
|
80
|
+
.filter(([key, entry]) => key !== keepKey && now - entry.lastUsedAt > MAX_IDLE_MS)
|
|
81
|
+
.sort((a, b) => a[1].lastUsedAt - b[1].lastUsedAt);
|
|
82
|
+
while (persistentStates.size - removable.length > MAX_PERSISTENT_STATES) {
|
|
83
|
+
const next = [...persistentStates.entries()]
|
|
84
|
+
.filter(([key]) => key !== keepKey && !removable.some(([candidate]) => candidate === key))
|
|
85
|
+
.sort((a, b) => a[1].lastUsedAt - b[1].lastUsedAt)[0];
|
|
86
|
+
if (!next)
|
|
87
|
+
break;
|
|
88
|
+
removable.push(next);
|
|
89
|
+
}
|
|
90
|
+
for (const [key, entry] of removable) {
|
|
91
|
+
persistentStates.delete(key);
|
|
92
|
+
void disposeBackgroundTaskState(entry.state.backgroundTasks);
|
|
93
|
+
entry.state.fileReads.entries.clear();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ============================================================
|
|
3
|
+
* src/session/sessionState.ts —— 会话级隔离状态
|
|
4
|
+
* ------------------------------------------------------------
|
|
5
|
+
* 把 reactiveCompact + microCompactLite 的可注入状态打包。
|
|
6
|
+
*
|
|
7
|
+
* 长生命周期宿主按 workspace + session 复用一份;一次性 CLI 可直接创建。
|
|
8
|
+
* 让每个 chatId 的工具结果去重缓存、文件读取证据和后台任务互不串扰。
|
|
9
|
+
* ============================================================
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
createMicroCompactState,
|
|
14
|
+
type MicroCompactState,
|
|
15
|
+
} from '../context/microCompactLite.js';
|
|
16
|
+
import {
|
|
17
|
+
createReactiveCompactState,
|
|
18
|
+
type ReactiveCompactState,
|
|
19
|
+
} from '../context/reactiveCompact.js';
|
|
20
|
+
import { createFileReadState, type FileReadState } from '../tools/shared/fileState.js';
|
|
21
|
+
import {
|
|
22
|
+
createBackgroundTaskState,
|
|
23
|
+
disposeBackgroundTaskState,
|
|
24
|
+
type BackgroundTaskState,
|
|
25
|
+
} from '../tools/tasks/backgroundTaskService.js';
|
|
26
|
+
import { createAgentTaskState, stopAllAgentTasks, type AgentTaskState } from '../tools/agent/agentTaskService.js';
|
|
27
|
+
|
|
28
|
+
export interface SessionState {
|
|
29
|
+
reactive: ReactiveCompactState;
|
|
30
|
+
microCompact: MicroCompactState;
|
|
31
|
+
fileReads: FileReadState;
|
|
32
|
+
backgroundTasks: BackgroundTaskState;
|
|
33
|
+
agentTasks: AgentTaskState;
|
|
34
|
+
/** Main-agent worktree changes the effective cwd without changing workspace identity. */
|
|
35
|
+
activeWorktree?: {
|
|
36
|
+
id: string;
|
|
37
|
+
path: string;
|
|
38
|
+
branch: string;
|
|
39
|
+
baseSha: string;
|
|
40
|
+
gitRoot: string;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function createSessionState(): SessionState {
|
|
45
|
+
return {
|
|
46
|
+
reactive: createReactiveCompactState(),
|
|
47
|
+
microCompact: createMicroCompactState(),
|
|
48
|
+
fileReads: createFileReadState(),
|
|
49
|
+
backgroundTasks: createBackgroundTaskState(),
|
|
50
|
+
agentTasks: createAgentTaskState(),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const persistentStates = new Map<string, { state: SessionState; lastUsedAt: number }>();
|
|
55
|
+
const MAX_PERSISTENT_STATES = 128;
|
|
56
|
+
const MAX_IDLE_MS = 24 * 60 * 60_000;
|
|
57
|
+
|
|
58
|
+
export interface SessionStateIdentity {
|
|
59
|
+
surface: string;
|
|
60
|
+
workspaceId?: string;
|
|
61
|
+
cwd?: string;
|
|
62
|
+
sessionId: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Collision-free durable key shared by Desktop, CLI and headless hosts. */
|
|
66
|
+
export function sessionStateKey(identity: SessionStateIdentity): string {
|
|
67
|
+
return JSON.stringify([
|
|
68
|
+
identity.surface,
|
|
69
|
+
identity.workspaceId ?? '',
|
|
70
|
+
identity.cwd ?? '',
|
|
71
|
+
identity.sessionId,
|
|
72
|
+
]);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Return process-local state scoped to a durable host session key. This keeps
|
|
77
|
+
* read evidence and background tasks available across user turns without ever
|
|
78
|
+
* sharing them between workspaces or conversations.
|
|
79
|
+
*/
|
|
80
|
+
export function getOrCreateSessionState(key: string): SessionState {
|
|
81
|
+
const now = Date.now();
|
|
82
|
+
let entry = persistentStates.get(key);
|
|
83
|
+
if (!entry) {
|
|
84
|
+
entry = { state: createSessionState(), lastUsedAt: now };
|
|
85
|
+
persistentStates.set(key, entry);
|
|
86
|
+
} else {
|
|
87
|
+
entry.lastUsedAt = now;
|
|
88
|
+
}
|
|
89
|
+
prunePersistentStates(now, key);
|
|
90
|
+
return entry.state;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export async function disposeSessionState(key: string): Promise<void> {
|
|
94
|
+
const entry = persistentStates.get(key);
|
|
95
|
+
if (!entry) return;
|
|
96
|
+
persistentStates.delete(key);
|
|
97
|
+
await disposeBackgroundTaskState(entry.state.backgroundTasks);
|
|
98
|
+
await stopAllAgentTasks(entry.state.agentTasks);
|
|
99
|
+
entry.state.fileReads.entries.clear();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export async function disposeAllSessionStates(): Promise<void> {
|
|
103
|
+
const entries = [...persistentStates.values()];
|
|
104
|
+
persistentStates.clear();
|
|
105
|
+
await Promise.all(entries.map(async ({ state }) => {
|
|
106
|
+
await disposeBackgroundTaskState(state.backgroundTasks);
|
|
107
|
+
await stopAllAgentTasks(state.agentTasks);
|
|
108
|
+
state.fileReads.entries.clear();
|
|
109
|
+
}));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export async function disposeDetachedSessionState(state: SessionState): Promise<void> {
|
|
113
|
+
await disposeBackgroundTaskState(state.backgroundTasks);
|
|
114
|
+
await stopAllAgentTasks(state.agentTasks);
|
|
115
|
+
state.fileReads.entries.clear();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function prunePersistentStates(now: number, keepKey: string): void {
|
|
119
|
+
const removable = [...persistentStates.entries()]
|
|
120
|
+
.filter(([key, entry]) => key !== keepKey && now - entry.lastUsedAt > MAX_IDLE_MS)
|
|
121
|
+
.sort((a, b) => a[1].lastUsedAt - b[1].lastUsedAt);
|
|
122
|
+
while (persistentStates.size - removable.length > MAX_PERSISTENT_STATES) {
|
|
123
|
+
const next = [...persistentStates.entries()]
|
|
124
|
+
.filter(([key]) => key !== keepKey && !removable.some(([candidate]) => candidate === key))
|
|
125
|
+
.sort((a, b) => a[1].lastUsedAt - b[1].lastUsedAt)[0];
|
|
126
|
+
if (!next) break;
|
|
127
|
+
removable.push(next);
|
|
128
|
+
}
|
|
129
|
+
for (const [key, entry] of removable) {
|
|
130
|
+
persistentStates.delete(key);
|
|
131
|
+
void disposeBackgroundTaskState(entry.state.backgroundTasks);
|
|
132
|
+
entry.state.fileReads.entries.clear();
|
|
133
|
+
}
|
|
134
|
+
}
|
package/src/toolGate.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ============================================================
|
|
3
|
+
* src/toolGate.ts —— 工具执行闸门(通用机制,零策略)
|
|
4
|
+
* ------------------------------------------------------------
|
|
5
|
+
* 一个可选的、社交无感的「工具执行前审批」缝:loop 在执行每个工具前,
|
|
6
|
+
* 若宿主注入了 toolGate,就先 await 它拿到 allow/deny。deny 时把 reason 当作
|
|
7
|
+
* tool_result 回填给模型(模型据此改道/如实报告),不抛异常、不中断整轮。
|
|
8
|
+
*
|
|
9
|
+
* 内核对「为什么要审批」一无所知——它只提供停下来问一句的机制。所有策略
|
|
10
|
+
* (谁能驱使这个 agent、要不要本机主人点头、信任名单)都在宿主(如 gateway 的
|
|
11
|
+
* 跨机指令同意闸门)里。这与 askBridge 同构:内核给机制,宿主给策略。
|
|
12
|
+
*
|
|
13
|
+
* 与 askBridge 的分工:askBridge 是**模型主动**调 AskUserQuestion 工具「问人类」;
|
|
14
|
+
* toolGate 是**宿主被动**在工具执行前「拦一道」——模型未必知道自己被审批。
|
|
15
|
+
* ============================================================
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
export interface ToolGateRequest {
|
|
19
|
+
/** 工具名(如 'Bash' / 'Edit')。 */
|
|
20
|
+
name: string;
|
|
21
|
+
/** 原始参数 JSON 串(宿主可解析出摘要给人类看,如 rm -rf src)。 */
|
|
22
|
+
argsJson: string;
|
|
23
|
+
/** 该工具是否只读,供宿主按自己的策略决定是否放行。 */
|
|
24
|
+
isReadOnly: boolean;
|
|
25
|
+
/** 本次 tool_call id。 */
|
|
26
|
+
toolCallId: string;
|
|
27
|
+
/** 宿主提供的运行作用域;模型参数不能伪造这些身份。 */
|
|
28
|
+
runContext?: {
|
|
29
|
+
ownerId: string;
|
|
30
|
+
conversationKey: string;
|
|
31
|
+
runId: string;
|
|
32
|
+
surface: 'desktop' | 'tui' | 'cli' | 'workflow' | 'subagent';
|
|
33
|
+
};
|
|
34
|
+
/** 受控工具可提供更细的动作语义,供宿主实施确认策略。 */
|
|
35
|
+
action?: {
|
|
36
|
+
kind: string;
|
|
37
|
+
targetApp?: string;
|
|
38
|
+
transmitsData?: boolean;
|
|
39
|
+
irreversible?: boolean;
|
|
40
|
+
capability?: string;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type ToolGateDecision = { allow: true } | { allow: false; reason: string };
|
|
45
|
+
|
|
46
|
+
/** 工具执行闸门:返回放行或(带原因的)拒绝。缺省不注入 = 全放行(行为不变)。 */
|
|
47
|
+
export type ToolGate = (
|
|
48
|
+
req: ToolGateRequest,
|
|
49
|
+
signal?: AbortSignal,
|
|
50
|
+
) => Promise<ToolGateDecision>;
|