hoomanjs 1.46.0 → 1.55.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 +44 -18
- package/dist/acp/acp-agent.d.ts +42 -0
- package/dist/acp/acp-agent.js +336 -47
- package/dist/acp/acp-agent.js.map +1 -1
- package/dist/acp/approvals.js +11 -10
- package/dist/acp/approvals.js.map +1 -1
- package/dist/acp/browser.d.ts +9 -0
- package/dist/acp/browser.js +23 -0
- package/dist/acp/browser.js.map +1 -0
- package/dist/acp/meta/vscode.d.ts +8 -7
- package/dist/acp/meta/vscode.js +10 -11
- package/dist/acp/meta/vscode.js.map +1 -1
- package/dist/acp/session-config.d.ts +2 -2
- package/dist/acp/session-config.js +24 -20
- package/dist/acp/session-config.js.map +1 -1
- package/dist/acp/sessions/store.d.ts +3 -3
- package/dist/acp/utils/tool-kind.js +8 -6
- package/dist/acp/utils/tool-kind.js.map +1 -1
- package/dist/chat/app.js +91 -11
- package/dist/chat/app.js.map +1 -1
- package/dist/chat/approvals.js +3 -0
- package/dist/chat/approvals.js.map +1 -1
- package/dist/chat/components/ApprovalPrompt.js +15 -25
- package/dist/chat/components/ApprovalPrompt.js.map +1 -1
- package/dist/chat/components/BackgroundJobsPanel.d.ts +10 -0
- package/dist/chat/components/BackgroundJobsPanel.js +15 -0
- package/dist/chat/components/BackgroundJobsPanel.js.map +1 -0
- package/dist/chat/components/BottomChrome.d.ts +6 -1
- package/dist/chat/components/BottomChrome.js +3 -2
- package/dist/chat/components/BottomChrome.js.map +1 -1
- package/dist/chat/components/ChromePicker.d.ts +7 -2
- package/dist/chat/components/ChromePicker.js +18 -2
- package/dist/chat/components/ChromePicker.js.map +1 -1
- package/dist/chat/components/Composer.js +3 -2
- package/dist/chat/components/Composer.js.map +1 -1
- package/dist/chat/components/DownloadPanel.js +2 -1
- package/dist/chat/components/DownloadPanel.js.map +1 -1
- package/dist/chat/components/EmptyChatBanner.js +2 -1
- package/dist/chat/components/EmptyChatBanner.js.map +1 -1
- package/dist/chat/components/PromptInput.js +2 -1
- package/dist/chat/components/PromptInput.js.map +1 -1
- package/dist/chat/components/QuestionPrompt.js +5 -4
- package/dist/chat/components/QuestionPrompt.js.map +1 -1
- package/dist/chat/components/QueuedPrompts.js +3 -2
- package/dist/chat/components/QueuedPrompts.js.map +1 -1
- package/dist/chat/components/ReasoningStrip.js +2 -1
- package/dist/chat/components/ReasoningStrip.js.map +1 -1
- package/dist/chat/components/RetryEvent.js +2 -1
- package/dist/chat/components/RetryEvent.js.map +1 -1
- package/dist/chat/components/SelectPicker.js +2 -1
- package/dist/chat/components/SelectPicker.js.map +1 -1
- package/dist/chat/components/ShellToolEvent.d.ts +12 -0
- package/dist/chat/components/ShellToolEvent.js +94 -0
- package/dist/chat/components/ShellToolEvent.js.map +1 -0
- package/dist/chat/components/SlashCommands.js +2 -1
- package/dist/chat/components/SlashCommands.js.map +1 -1
- package/dist/chat/components/Spinner.js +2 -1
- package/dist/chat/components/Spinner.js.map +1 -1
- package/dist/chat/components/StatusBar.js +19 -15
- package/dist/chat/components/StatusBar.js.map +1 -1
- package/dist/chat/components/ThinkingStatus.js +2 -1
- package/dist/chat/components/ThinkingStatus.js.map +1 -1
- package/dist/chat/components/ThoughtEvent.js +2 -1
- package/dist/chat/components/ThoughtEvent.js.map +1 -1
- package/dist/chat/components/TodoPanel.js +2 -1
- package/dist/chat/components/TodoPanel.js.map +1 -1
- package/dist/chat/components/ToolEvent.d.ts +2 -1
- package/dist/chat/components/ToolEvent.js +9 -2
- package/dist/chat/components/ToolEvent.js.map +1 -1
- package/dist/chat/components/ToolEventFileResult.js +8 -7
- package/dist/chat/components/ToolEventFileResult.js.map +1 -1
- package/dist/chat/components/Transcript.d.ts +4 -2
- package/dist/chat/components/Transcript.js +4 -4
- package/dist/chat/components/Transcript.js.map +1 -1
- package/dist/chat/components/markdown/BlockRenderer.js +3 -2
- package/dist/chat/components/markdown/BlockRenderer.js.map +1 -1
- package/dist/chat/components/markdown/CodeBlock.js +3 -2
- package/dist/chat/components/markdown/CodeBlock.js.map +1 -1
- package/dist/chat/components/markdown/InlineRenderer.js +6 -5
- package/dist/chat/components/markdown/InlineRenderer.js.map +1 -1
- package/dist/chat/components/shared.js +7 -6
- package/dist/chat/components/shared.js.map +1 -1
- package/dist/chat/types.d.ts +7 -0
- package/dist/cli.js +162 -44
- package/dist/cli.js.map +1 -1
- package/dist/configure/app.js +46 -29
- package/dist/configure/app.js.map +1 -1
- package/dist/configure/components/BusyScreen.js +2 -1
- package/dist/configure/components/BusyScreen.js.map +1 -1
- package/dist/configure/components/MenuScreen.js +3 -2
- package/dist/configure/components/MenuScreen.js.map +1 -1
- package/dist/configure/components/PromptForm.js +2 -1
- package/dist/configure/components/PromptForm.js.map +1 -1
- package/dist/configure/components/SelectMenuItem.js +4 -3
- package/dist/configure/components/SelectMenuItem.js.map +1 -1
- package/dist/configure/utils.js +4 -3
- package/dist/configure/utils.js.map +1 -1
- package/dist/core/agent/default-retry-strategy.js +46 -12
- package/dist/core/agent/default-retry-strategy.js.map +1 -1
- package/dist/core/agent/gitignore-guard-plugin.js +17 -2
- package/dist/core/agent/gitignore-guard-plugin.js.map +1 -1
- package/dist/core/agent/index.js +38 -7
- package/dist/core/agent/index.js.map +1 -1
- package/dist/core/approvals/allowlist.js +1 -0
- package/dist/core/approvals/allowlist.js.map +1 -1
- package/dist/core/approvals/intervention.d.ts +10 -2
- package/dist/core/approvals/intervention.js +46 -8
- package/dist/core/approvals/intervention.js.map +1 -1
- package/dist/core/config.d.ts +9 -2
- package/dist/core/config.js +8 -4
- package/dist/core/config.js.map +1 -1
- package/dist/core/index.d.ts +2 -2
- package/dist/core/mcp/oauth/service.js +2 -2
- package/dist/core/mcp/oauth/service.js.map +1 -1
- package/dist/core/models/bedrock.js +6 -0
- package/dist/core/models/bedrock.js.map +1 -1
- package/dist/core/models/groq.js +34 -14
- package/dist/core/models/groq.js.map +1 -1
- package/dist/core/models/minimax.js +1 -1
- package/dist/core/models/minimax.js.map +1 -1
- package/dist/core/models/types.d.ts +10 -2
- package/dist/core/models/types.js +1 -0
- package/dist/core/models/types.js.map +1 -1
- package/dist/core/modes/definitions.d.ts +4 -2
- package/dist/core/modes/definitions.js +77 -9
- package/dist/core/modes/definitions.js.map +1 -1
- package/dist/core/modes/index.d.ts +1 -1
- package/dist/core/modes/index.js +1 -1
- package/dist/core/modes/index.js.map +1 -1
- package/dist/core/modes/registry.js +4 -9
- package/dist/core/modes/registry.js.map +1 -1
- package/dist/core/modes/schema.d.ts +1 -1
- package/dist/core/modes/schema.js +1 -1
- package/dist/core/modes/schema.js.map +1 -1
- package/dist/core/prompts/agents/{review.md → code-review.md} +2 -2
- package/dist/core/prompts/agents/design-review.md +35 -0
- package/dist/core/prompts/agents/{test-investigator.md → quality-analyst.md} +2 -2
- package/dist/core/prompts/modes/agent.md +2 -0
- package/dist/core/prompts/modes/ask.md +2 -2
- package/dist/core/prompts/modes/design.md +37 -0
- package/dist/core/prompts/modes/plan.md +5 -5
- package/dist/core/prompts/{runtime.js → runtime/agents.js} +2 -2
- package/dist/core/prompts/runtime/agents.js.map +1 -0
- package/dist/core/prompts/runtime/design.d.ts +11 -0
- package/dist/core/prompts/runtime/design.js +78 -0
- package/dist/core/prompts/runtime/design.js.map +1 -0
- package/dist/core/prompts/{session-mode-appendix.js → session-mode.js} +1 -1
- package/dist/core/prompts/session-mode.js.map +1 -0
- package/dist/core/prompts/static/ask-user.md +3 -2
- package/dist/core/prompts/static/fetch.md +2 -1
- package/dist/core/prompts/static/filesystem.md +2 -1
- package/dist/core/prompts/static/shell.md +21 -1
- package/dist/core/prompts/static/subagents.md +2 -1
- package/dist/core/prompts/static/switch-mode.md +10 -0
- package/dist/core/prompts/system.d.ts +1 -0
- package/dist/core/prompts/system.js +11 -3
- package/dist/core/prompts/system.js.map +1 -1
- package/dist/core/shell/index.d.ts +7 -0
- package/dist/core/shell/index.js +6 -0
- package/dist/core/shell/index.js.map +1 -0
- package/dist/core/shell/manager.d.ts +23 -0
- package/dist/core/shell/manager.js +604 -0
- package/dist/core/shell/manager.js.map +1 -0
- package/dist/core/shell/output-buffer.d.ts +30 -0
- package/dist/core/shell/output-buffer.js +116 -0
- package/dist/core/shell/output-buffer.js.map +1 -0
- package/dist/core/shell/registry.d.ts +5 -0
- package/dist/core/shell/registry.js +24 -0
- package/dist/core/shell/registry.js.map +1 -0
- package/dist/core/{tools/shell.d.ts → shell/terminal-backend.d.ts} +20 -18
- package/dist/core/shell/terminal-backend.js +18 -0
- package/dist/core/shell/terminal-backend.js.map +1 -0
- package/dist/core/shell/tools.d.ts +41 -0
- package/dist/core/{tools/shell.js → shell/tools.js} +186 -11
- package/dist/core/shell/tools.js.map +1 -0
- package/dist/core/shell/types.d.ts +95 -0
- package/dist/core/shell/types.js +2 -0
- package/dist/core/shell/types.js.map +1 -0
- package/dist/core/skills/built-in/hooman-config/SKILL.md +30 -35
- package/dist/core/skills/built-in/hooman-config/search.md +5 -3
- package/dist/core/skills/built-in/hooman-design/SKILL.md +97 -0
- package/dist/core/skills/built-in/hooman-design/assets/article-shell.html +87 -0
- package/dist/core/skills/built-in/hooman-design/assets/auth-shell.html +143 -0
- package/dist/core/skills/built-in/hooman-design/assets/business-card-shell.html +112 -0
- package/dist/core/skills/built-in/hooman-design/assets/contact-shell.html +181 -0
- package/dist/core/skills/built-in/hooman-design/assets/dashboard-shell.html +90 -0
- package/dist/core/skills/built-in/hooman-design/assets/data-table-shell.html +114 -0
- package/dist/core/skills/built-in/hooman-design/assets/deck-shell.html +187 -0
- package/dist/core/skills/built-in/hooman-design/assets/dialog-shell.html +98 -0
- package/dist/core/skills/built-in/hooman-design/assets/email-shell.html +101 -0
- package/dist/core/skills/built-in/hooman-design/assets/empty-state-shell.html +92 -0
- package/dist/core/skills/built-in/hooman-design/assets/flyer-shell.html +168 -0
- package/dist/core/skills/built-in/hooman-design/assets/invite-shell.html +167 -0
- package/dist/core/skills/built-in/hooman-design/assets/landing-shell.html +184 -0
- package/dist/core/skills/built-in/hooman-design/assets/mobile-frame-shell.html +109 -0
- package/dist/core/skills/built-in/hooman-design/assets/newsletter-shell.html +141 -0
- package/dist/core/skills/built-in/hooman-design/assets/onboarding-shell.html +131 -0
- package/dist/core/skills/built-in/hooman-design/assets/pricing-shell.html +160 -0
- package/dist/core/skills/built-in/hooman-design/assets/prototype-shell.html +83 -0
- package/dist/core/skills/built-in/hooman-design/assets/resume-shell.html +228 -0
- package/dist/core/skills/built-in/hooman-design/assets/settings-shell.html +196 -0
- package/dist/core/skills/built-in/hooman-design/assets/tokens/botanical-calm.css +34 -0
- package/dist/core/skills/built-in/hooman-design/assets/tokens/copper-ledger.css +34 -0
- package/dist/core/skills/built-in/hooman-design/assets/tokens/editorial-ink.css +34 -0
- package/dist/core/skills/built-in/hooman-design/assets/tokens/fintech-clear.css +34 -0
- package/dist/core/skills/built-in/hooman-design/assets/tokens/harbor-navy.css +35 -0
- package/dist/core/skills/built-in/hooman-design/assets/tokens/midnight-editorial.css +34 -0
- package/dist/core/skills/built-in/hooman-design/assets/tokens/night-console.css +34 -0
- package/dist/core/skills/built-in/hooman-design/assets/tokens/paper-mono.css +35 -0
- package/dist/core/skills/built-in/hooman-design/assets/tokens/signal-mono.css +34 -0
- package/dist/core/skills/built-in/hooman-design/assets/tokens/soft-product.css +34 -0
- package/dist/core/skills/built-in/hooman-design/assets/tokens/swiss-grid.css +34 -0
- package/dist/core/skills/built-in/hooman-design/assets/tokens/warm-atelier.css +34 -0
- package/dist/core/skills/built-in/hooman-design/assets/waitlist-shell.html +139 -0
- package/dist/core/skills/built-in/hooman-design/craft/accessibility-baseline.md +32 -0
- package/dist/core/skills/built-in/hooman-design/craft/anti-ai-slop.md +27 -0
- package/dist/core/skills/built-in/hooman-design/craft/color-surfaces.md +45 -0
- package/dist/core/skills/built-in/hooman-design/craft/data-viz.md +24 -0
- package/dist/core/skills/built-in/hooman-design/craft/deck-slides.md +46 -0
- package/dist/core/skills/built-in/hooman-design/craft/forms-validation.md +35 -0
- package/dist/core/skills/built-in/hooman-design/craft/iconography.md +19 -0
- package/dist/core/skills/built-in/hooman-design/craft/layout-overflow.md +31 -0
- package/dist/core/skills/built-in/hooman-design/craft/motion.md +41 -0
- package/dist/core/skills/built-in/hooman-design/craft/print.md +37 -0
- package/dist/core/skills/built-in/hooman-design/craft/responsive.md +30 -0
- package/dist/core/skills/built-in/hooman-design/craft/spacing-density.md +46 -0
- package/dist/core/skills/built-in/hooman-design/craft/state-coverage.md +21 -0
- package/dist/core/skills/built-in/hooman-design/craft/typography.md +73 -0
- package/dist/core/skills/built-in/hooman-design/directions.md +115 -0
- package/dist/core/skills/built-in/hooman-design/references/artifact-layout.md +15 -0
- package/dist/core/skills/built-in/hooman-design/references/export.md +47 -0
- package/dist/core/skills/built-in/hooman-design/references/workflow.md +80 -0
- package/dist/core/skills/built-in/hooman-mcp/SKILL.md +2 -2
- package/dist/core/state/llm-modality.d.ts +13 -0
- package/dist/core/state/llm-modality.js +19 -0
- package/dist/core/state/llm-modality.js.map +1 -0
- package/dist/core/state/plan.d.ts +1 -1
- package/dist/core/state/plan.js +1 -1
- package/dist/core/state/shell-jobs.d.ts +9 -0
- package/dist/core/state/shell-jobs.js +20 -0
- package/dist/core/state/shell-jobs.js.map +1 -0
- package/dist/core/state/tool-approvals.d.ts +12 -9
- package/dist/core/state/tool-approvals.js +94 -52
- package/dist/core/state/tool-approvals.js.map +1 -1
- package/dist/core/state/turn-boundaries.d.ts +33 -0
- package/dist/core/state/turn-boundaries.js +49 -0
- package/dist/core/state/turn-boundaries.js.map +1 -0
- package/dist/core/subagents/index.d.ts +1 -1
- package/dist/core/subagents/index.js +1 -1
- package/dist/core/subagents/registry.js +15 -6
- package/dist/core/subagents/registry.js.map +1 -1
- package/dist/core/subagents/tool.d.ts +8 -2
- package/dist/core/subagents/tool.js +93 -44
- package/dist/core/subagents/tool.js.map +1 -1
- package/dist/core/theme.d.ts +14 -0
- package/dist/core/theme.js +14 -0
- package/dist/core/theme.js.map +1 -0
- package/dist/core/tools/ask-user.d.ts +1 -1
- package/dist/core/tools/ask-user.js +1 -1
- package/dist/core/tools/export.d.ts +8 -0
- package/dist/core/tools/export.js +202 -0
- package/dist/core/tools/export.js.map +1 -0
- package/dist/core/tools/fetch.d.ts +2 -0
- package/dist/core/tools/fetch.js +92 -55
- package/dist/core/tools/fetch.js.map +1 -1
- package/dist/core/tools/filesystem.d.ts +2 -1
- package/dist/core/tools/filesystem.js +38 -4
- package/dist/core/tools/filesystem.js.map +1 -1
- package/dist/core/tools/index.d.ts +3 -2
- package/dist/core/tools/index.js +3 -2
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/preview.d.ts +10 -0
- package/dist/core/tools/preview.js +147 -0
- package/dist/core/tools/preview.js.map +1 -0
- package/dist/core/tools/switch-mode.d.ts +6 -0
- package/dist/core/tools/switch-mode.js +188 -0
- package/dist/core/tools/switch-mode.js.map +1 -0
- package/dist/core/tools/web-search.js +176 -0
- package/dist/core/tools/web-search.js.map +1 -1
- package/dist/core/utils/browser.d.ts +8 -1
- package/dist/core/utils/browser.js +17 -1
- package/dist/core/utils/browser.js.map +1 -1
- package/dist/core/utils/export-design.d.ts +40 -0
- package/dist/core/utils/export-design.js +188 -0
- package/dist/core/utils/export-design.js.map +1 -0
- package/dist/core/utils/export-figma.d.ts +17 -0
- package/dist/core/utils/export-figma.js +189 -0
- package/dist/core/utils/export-figma.js.map +1 -0
- package/dist/core/utils/export-sketch.d.ts +11 -0
- package/dist/core/utils/export-sketch.js +456 -0
- package/dist/core/utils/export-sketch.js.map +1 -0
- package/dist/core/utils/fig-archive.d.ts +47 -0
- package/dist/core/utils/fig-archive.js +181 -0
- package/dist/core/utils/fig-archive.js.map +1 -0
- package/dist/core/utils/metadata.d.ts +30 -0
- package/dist/core/utils/metadata.js +122 -0
- package/dist/core/utils/metadata.js.map +1 -1
- package/dist/core/utils/models-prefetch.d.ts +53 -0
- package/dist/core/utils/models-prefetch.js +469 -0
- package/dist/core/utils/models-prefetch.js.map +1 -0
- package/dist/core/utils/onboarding-config.d.ts +48 -0
- package/dist/core/utils/onboarding-config.js +373 -0
- package/dist/core/utils/onboarding-config.js.map +1 -0
- package/dist/core/utils/paths.d.ts +9 -7
- package/dist/core/utils/paths.js +12 -10
- package/dist/core/utils/paths.js.map +1 -1
- package/dist/core/utils/preview-server.d.ts +20 -0
- package/dist/core/utils/preview-server.js +212 -0
- package/dist/core/utils/preview-server.js.map +1 -0
- package/dist/core/utils/search-probe.d.ts +19 -0
- package/dist/core/utils/search-probe.js +165 -0
- package/dist/core/utils/search-probe.js.map +1 -0
- package/dist/core/utils/seeds/empty-slides.deck +0 -0
- package/dist/core/utils/url-safety.d.ts +2 -0
- package/dist/core/utils/url-safety.js +47 -0
- package/dist/core/utils/url-safety.js.map +1 -0
- package/dist/core/utils/zstd.d.ts +6 -0
- package/dist/core/utils/zstd.js +39 -0
- package/dist/core/utils/zstd.js.map +1 -0
- package/dist/exec/approvals.js +5 -5
- package/dist/exec/approvals.js.map +1 -1
- package/dist/index.d.ts +11 -5
- package/dist/index.js +8 -5
- package/dist/index.js.map +1 -1
- package/dist/onboarding/app.d.ts +5 -0
- package/dist/onboarding/app.js +255 -0
- package/dist/onboarding/app.js.map +1 -0
- package/dist/onboarding/index.d.ts +5 -0
- package/dist/onboarding/index.js +27 -0
- package/dist/onboarding/index.js.map +1 -0
- package/package.json +16 -3
- package/dist/core/prompts/runtime.js.map +0 -1
- package/dist/core/prompts/session-mode-appendix.js.map +0 -1
- package/dist/core/prompts/static/planning.md +0 -3
- package/dist/core/tools/plan.d.ts +0 -5
- package/dist/core/tools/plan.js +0 -150
- package/dist/core/tools/plan.js.map +0 -1
- package/dist/core/tools/shell.js.map +0 -1
- /package/dist/core/prompts/{runtime.d.ts → runtime/agents.d.ts} +0 -0
- /package/dist/core/prompts/{session-mode-appendix.d.ts → session-mode.d.ts} +0 -0
package/dist/acp/acp-agent.js
CHANGED
|
@@ -9,6 +9,8 @@ import { MODE_DEFINITIONS } from "../core/modes/definitions.js";
|
|
|
9
9
|
import { DEFAULT_SESSION_MODE, isKnownSessionMode, } from "../core/modes/schema.js";
|
|
10
10
|
import { getModeState, setSessionMode } from "../core/state/session-mode.js";
|
|
11
11
|
import { isYoloEnabled, setYoloEnabled } from "../core/state/yolo.js";
|
|
12
|
+
import { setLlmModality } from "../core/state/llm-modality.js";
|
|
13
|
+
import { dropTurnBoundariesFrom, getTurnBoundary, recordTurnBoundary, } from "../core/state/turn-boundaries.js";
|
|
12
14
|
import { ChatTurnSteeringController, createChatTurnSteeringIntervention, } from "../core/agent/turn-steering.js";
|
|
13
15
|
import { getAgentConversationManager, getAgentSessionManager, } from "../core/agent/index.js";
|
|
14
16
|
import { readBundledPrompt } from "../core/prompts/bundled.js";
|
|
@@ -17,10 +19,10 @@ import { subscribeModelDownloadProgress, } from "../core/utils/download-progress
|
|
|
17
19
|
import { subscribeModelRetryProgress, } from "../core/agent/retry-progress.js";
|
|
18
20
|
import { toAdditiveUsage } from "../core/utils/usage.js";
|
|
19
21
|
import { computeUsageCostUsd, configuredLlmContext, contextTokensFromUsage, resolveLlmMetadata, } from "../core/utils/metadata.js";
|
|
20
|
-
import { buildSessionConfigOptions, currentModelName, CONFIG_ID_EFFORT, CONFIG_ID_MODE, CONFIG_ID_MODEL,
|
|
22
|
+
import { buildSessionConfigOptions, currentModelName, CONFIG_ID_EFFORT, CONFIG_ID_MODE, CONFIG_ID_MODEL, CONFIG_ID_YOLO, } from "./session-config.js";
|
|
21
23
|
import { activeProviderName, parseReasoningEffortArg, withReasoningEffort, } from "../core/utils/reasoning-effort.js";
|
|
22
24
|
import { ACP_SLASH_COMMANDS, parseAcpSlashCommand, } from "./commands.js";
|
|
23
|
-
import {
|
|
25
|
+
import { SWITCH_MODE_TOOL } from "../core/state/tool-approvals.js";
|
|
24
26
|
import { runWithCwd } from "../core/utils/cwd-context.js";
|
|
25
27
|
import { runWithAgentMemoryScope } from "../core/memory/index.js";
|
|
26
28
|
import { createSessionConfig, } from "../core/session-config.js";
|
|
@@ -32,12 +34,14 @@ import { takeFileToolDisplay } from "../core/state/file-tool-display.js";
|
|
|
32
34
|
import { getTodoViewState } from "../core/state/todos.js";
|
|
33
35
|
import { UPDATE_TODOS_TOOL_NAME } from "../core/tools/todo.js";
|
|
34
36
|
import { setAskUserBackend } from "../core/tools/ask-user.js";
|
|
37
|
+
import { setBrowserPreviewBackend } from "../core/utils/browser.js";
|
|
35
38
|
import { setTextFsBackend } from "../core/tools/filesystem.js";
|
|
36
|
-
import { setTerminalBackend, } from "../core/
|
|
39
|
+
import { setTerminalBackend, clearShellJobManager, getShellJobManager, } from "../core/shell/index.js";
|
|
37
40
|
import { createAcpToolApprovalIntervention } from "./approvals.js";
|
|
38
41
|
import { createAcpAskUserBackend } from "./questions.js";
|
|
42
|
+
import { createAcpBrowserPreviewBackend } from "./browser.js";
|
|
39
43
|
import { extractAcpClientUserId } from "./meta/user-id.js";
|
|
40
|
-
import {
|
|
44
|
+
import { isAcpVscodeHost } from "./meta/vscode.js";
|
|
41
45
|
import { deriveSessionTitleFromEcho } from "./sessions/title.js";
|
|
42
46
|
import { acpPromptEchoText, acpPromptToInvokeArgs } from "./prompt-invoke.js";
|
|
43
47
|
import { normalizeAcpSessionMcpServers } from "./mcp-servers.js";
|
|
@@ -338,6 +342,7 @@ export class HoomanAcpAgent {
|
|
|
338
342
|
if (record) {
|
|
339
343
|
this.#sessions.delete(params.sessionId);
|
|
340
344
|
record.turnAbort?.abort();
|
|
345
|
+
await this.#teardownShellJobs(params.sessionId, record);
|
|
341
346
|
await record.mcpDisconnect();
|
|
342
347
|
}
|
|
343
348
|
await deleteSessionEntry(this.#acpRoot, params.sessionId);
|
|
@@ -352,7 +357,7 @@ export class HoomanAcpAgent {
|
|
|
352
357
|
const sessionId = crypto.randomUUID();
|
|
353
358
|
const clientUserId = extractAcpClientUserId(params._meta) ?? null;
|
|
354
359
|
const mcpServers = normalizeAcpSessionMcpServers(params.mcpServers);
|
|
355
|
-
const vscode =
|
|
360
|
+
const vscode = isAcpVscodeHost();
|
|
356
361
|
const mode = DEFAULT_SESSION_MODE;
|
|
357
362
|
const now = new Date().toISOString();
|
|
358
363
|
const entry = {
|
|
@@ -369,6 +374,7 @@ export class HoomanAcpAgent {
|
|
|
369
374
|
await writeSessionEntry(this.#acpRoot, entry);
|
|
370
375
|
const record = await this.#bootstrapSession(sessionId, params.cwd, clientUserId ?? sessionId, mcpServers, mode, undefined, vscode);
|
|
371
376
|
this.#sessions.set(sessionId, record);
|
|
377
|
+
this.#subscribeShellJobs(record.agent, this.#requireClient(), sessionId);
|
|
372
378
|
await this.#advertiseCommands(this.#requireClient(), sessionId);
|
|
373
379
|
return {
|
|
374
380
|
sessionId,
|
|
@@ -402,7 +408,7 @@ export class HoomanAcpAgent {
|
|
|
402
408
|
const mcpServers = params.mcpServers && params.mcpServers.length > 0
|
|
403
409
|
? normalizeAcpSessionMcpServers(params.mcpServers)
|
|
404
410
|
: (sourceEntry.mcpServers ?? []);
|
|
405
|
-
const vscode =
|
|
411
|
+
const vscode = isAcpVscodeHost();
|
|
406
412
|
const mode = resolveSessionMode(sourceEntry.sessionMode);
|
|
407
413
|
const now = new Date().toISOString();
|
|
408
414
|
const title = sourceEntry.title
|
|
@@ -449,6 +455,58 @@ export class HoomanAcpAgent {
|
|
|
449
455
|
configOptions: buildSessionConfigOptions(forkConfig, mode, sourceEntry.yolo === true),
|
|
450
456
|
};
|
|
451
457
|
}
|
|
458
|
+
/**
|
|
459
|
+
* Turn revert (custom `_hoomanjs/rewind_session` method, not part
|
|
460
|
+
* of the ACP spec): splice `agent.messages` back to the message index
|
|
461
|
+
* bookmarked for `messageId` (see {@link recordTurnBoundary}), dropping
|
|
462
|
+
* that turn and every turn after it, then persist the trimmed history.
|
|
463
|
+
*
|
|
464
|
+
* Returns `reverted: false` instead of erroring when `messageId` has no
|
|
465
|
+
* recorded boundary — e.g. the session was reloaded since that turn ran,
|
|
466
|
+
* so its in-memory bookmark (and the client's matching file-edit
|
|
467
|
+
* baselines) no longer exist.
|
|
468
|
+
*/
|
|
469
|
+
async rewindSession(params) {
|
|
470
|
+
const rec = this.#sessions.get(params.sessionId);
|
|
471
|
+
if (!rec) {
|
|
472
|
+
throw RequestError.invalidParams({ sessionId: params.sessionId });
|
|
473
|
+
}
|
|
474
|
+
if (this.#isTurnActive(rec)) {
|
|
475
|
+
throw RequestError.invalidParams({
|
|
476
|
+
sessionId: params.sessionId,
|
|
477
|
+
message: "Cannot rewind a session while a turn is still running.",
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
const boundary = getTurnBoundary(rec.agent, params.messageId);
|
|
481
|
+
if (boundary === undefined) {
|
|
482
|
+
return { reverted: false };
|
|
483
|
+
}
|
|
484
|
+
rec.agent.messages.length = boundary;
|
|
485
|
+
dropTurnBoundariesFrom(rec.agent, params.messageId);
|
|
486
|
+
await getAgentSessionManager(rec.agent)?.saveSnapshot({
|
|
487
|
+
target: rec.agent,
|
|
488
|
+
isLatest: true,
|
|
489
|
+
});
|
|
490
|
+
return { reverted: true };
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Custom `_hoomanjs/stop_shell_job`: stop a background shell job by id.
|
|
494
|
+
* Routes through {@link ShellJobManager.stop}, which kills the host terminal
|
|
495
|
+
* (process group) and emits the completion notification the UI listens for.
|
|
496
|
+
*/
|
|
497
|
+
async stopShellJob(params) {
|
|
498
|
+
const rec = this.#sessions.get(params.sessionId);
|
|
499
|
+
if (!rec) {
|
|
500
|
+
throw RequestError.invalidParams({ sessionId: params.sessionId });
|
|
501
|
+
}
|
|
502
|
+
const manager = getShellJobManager(rec.agent);
|
|
503
|
+
const existing = manager.get(params.jobId);
|
|
504
|
+
if (!existing) {
|
|
505
|
+
return { stopped: false };
|
|
506
|
+
}
|
|
507
|
+
await manager.stop(params.jobId);
|
|
508
|
+
return { stopped: true };
|
|
509
|
+
}
|
|
452
510
|
async loadSession(params, client) {
|
|
453
511
|
const { record, mode } = await this.#reactivateSession({
|
|
454
512
|
sessionId: params.sessionId,
|
|
@@ -489,6 +547,7 @@ export class HoomanAcpAgent {
|
|
|
489
547
|
if (record) {
|
|
490
548
|
this.#sessions.delete(params.sessionId);
|
|
491
549
|
record.turnAbort?.abort();
|
|
550
|
+
await this.#teardownShellJobs(params.sessionId, record);
|
|
492
551
|
await record.mcpDisconnect();
|
|
493
552
|
}
|
|
494
553
|
return {};
|
|
@@ -512,7 +571,7 @@ export class HoomanAcpAgent {
|
|
|
512
571
|
const mcpServers = params.mcpServers.length > 0
|
|
513
572
|
? normalizeAcpSessionMcpServers(params.mcpServers)
|
|
514
573
|
: (existing.mcpServers ?? []);
|
|
515
|
-
const vscode =
|
|
574
|
+
const vscode = isAcpVscodeHost();
|
|
516
575
|
const mode = resolveSessionMode(existing.sessionMode);
|
|
517
576
|
// Bootstrapping restores the Strands snapshot (messages + appState) during
|
|
518
577
|
// `agent.initialize()` — the snapshot is the conversation source of truth.
|
|
@@ -529,6 +588,7 @@ export class HoomanAcpAgent {
|
|
|
529
588
|
await replayConversationHistory(client, params.sessionId, record.agent.messages);
|
|
530
589
|
}
|
|
531
590
|
this.#sessions.set(params.sessionId, record);
|
|
591
|
+
this.#subscribeShellJobs(record.agent, client, params.sessionId);
|
|
532
592
|
await patchSessionEntry(this.#acpRoot, params.sessionId, {
|
|
533
593
|
cwd: params.cwd,
|
|
534
594
|
...(fromRequest !== undefined ? { userId: fromRequest || null } : {}),
|
|
@@ -581,6 +641,27 @@ export class HoomanAcpAgent {
|
|
|
581
641
|
if (!rec) {
|
|
582
642
|
throw RequestError.invalidParams({ sessionId: params.sessionId });
|
|
583
643
|
}
|
|
644
|
+
// Yolo is a boolean toggle (auto-approve all tool calls), so it carries a
|
|
645
|
+
// boolean value rather than a string one; handle it before the string
|
|
646
|
+
// guard below that the select-style options rely on.
|
|
647
|
+
if (params.configId === CONFIG_ID_YOLO) {
|
|
648
|
+
if (typeof params.value !== "boolean") {
|
|
649
|
+
throw RequestError.invalidParams({
|
|
650
|
+
configId: params.configId,
|
|
651
|
+
message: `Config option "${params.configId}" expects a boolean value`,
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
const enabled = params.value;
|
|
655
|
+
if (isYoloEnabled(rec.agent) !== enabled) {
|
|
656
|
+
setYoloEnabled(rec.agent, enabled);
|
|
657
|
+
await patchSessionEntry(this.#acpRoot, params.sessionId, {
|
|
658
|
+
yolo: enabled,
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
return {
|
|
662
|
+
configOptions: buildSessionConfigOptions(rec.config, resolveSessionMode(getModeState(rec.agent).mode), isYoloEnabled(rec.agent)),
|
|
663
|
+
};
|
|
664
|
+
}
|
|
584
665
|
if (typeof params.value !== "string") {
|
|
585
666
|
throw RequestError.invalidParams({
|
|
586
667
|
configId: params.configId,
|
|
@@ -589,39 +670,16 @@ export class HoomanAcpAgent {
|
|
|
589
670
|
}
|
|
590
671
|
const value = params.value;
|
|
591
672
|
if (params.configId === CONFIG_ID_MODE) {
|
|
592
|
-
if (value
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
await this.#syncCurrentMode(client, params.sessionId, rec);
|
|
598
|
-
}
|
|
599
|
-
if (!isYoloEnabled(rec.agent)) {
|
|
600
|
-
setYoloEnabled(rec.agent, true);
|
|
601
|
-
await patchSessionEntry(this.#acpRoot, params.sessionId, {
|
|
602
|
-
yolo: true,
|
|
603
|
-
});
|
|
604
|
-
}
|
|
673
|
+
if (!isKnownSessionMode(value)) {
|
|
674
|
+
throw RequestError.invalidParams({
|
|
675
|
+
value,
|
|
676
|
+
message: `Unknown mode "${value}"`,
|
|
677
|
+
});
|
|
605
678
|
}
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
message: `Unknown mode "${value}"`,
|
|
611
|
-
});
|
|
612
|
-
}
|
|
613
|
-
if (this.#transitionMode(rec, value)) {
|
|
614
|
-
// Keep the legacy `modes` surface in sync too (see Session Config
|
|
615
|
-
// Options spec: "Agents SHOULD keep both in sync").
|
|
616
|
-
await this.#syncCurrentMode(client, params.sessionId, rec);
|
|
617
|
-
}
|
|
618
|
-
// Selecting a plain mode always turns yolo back off.
|
|
619
|
-
if (isYoloEnabled(rec.agent)) {
|
|
620
|
-
setYoloEnabled(rec.agent, false);
|
|
621
|
-
await patchSessionEntry(this.#acpRoot, params.sessionId, {
|
|
622
|
-
yolo: false,
|
|
623
|
-
});
|
|
624
|
-
}
|
|
679
|
+
if (this.#transitionMode(rec, value)) {
|
|
680
|
+
// Keep the legacy `modes` surface in sync too (see Session Config
|
|
681
|
+
// Options spec: "Agents SHOULD keep both in sync").
|
|
682
|
+
await this.#syncCurrentMode(client, params.sessionId, rec);
|
|
625
683
|
}
|
|
626
684
|
}
|
|
627
685
|
else if (params.configId === CONFIG_ID_MODEL) {
|
|
@@ -788,6 +846,7 @@ export class HoomanAcpAgent {
|
|
|
788
846
|
const provider = await modelProviders[resolved.provider]();
|
|
789
847
|
rec.agent.model = provider.create(resolved.providerOptions, resolved.llmOptions);
|
|
790
848
|
rec.metadata = await resolveLlmMetadata(resolved.metadata, resolved.llmOptions.model, resolved.provider, configuredLlmContext(resolved)).catch(() => null);
|
|
849
|
+
setLlmModality(rec.agent, rec.metadata?.modality);
|
|
791
850
|
}
|
|
792
851
|
catch (error) {
|
|
793
852
|
if (previous) {
|
|
@@ -937,11 +996,13 @@ export class HoomanAcpAgent {
|
|
|
937
996
|
let stopReason = "end_turn";
|
|
938
997
|
try {
|
|
939
998
|
const echo = acpPromptEchoText(params.prompt);
|
|
999
|
+
let turnMessageId;
|
|
940
1000
|
if (echo.length > 0) {
|
|
1001
|
+
turnMessageId = crypto.randomUUID();
|
|
941
1002
|
await this.#sendUpdate(client, params.sessionId, {
|
|
942
1003
|
sessionUpdate: "user_message_chunk",
|
|
943
1004
|
content: { type: "text", text: echo },
|
|
944
|
-
messageId:
|
|
1005
|
+
messageId: turnMessageId,
|
|
945
1006
|
});
|
|
946
1007
|
await this.#maybeDeriveTitle(client, params.sessionId, echo);
|
|
947
1008
|
}
|
|
@@ -969,6 +1030,14 @@ export class HoomanAcpAgent {
|
|
|
969
1030
|
},
|
|
970
1031
|
], rec.metadata)
|
|
971
1032
|
: acpPromptToInvokeArgs(params.prompt, rec.metadata);
|
|
1033
|
+
// The `messageId` we just generated for this turn's user_message_chunk
|
|
1034
|
+
// echo (see the ACP MessageId RFD) doubles as a durable handle for
|
|
1035
|
+
// Turn revert: bookmark where this turn's messages start,
|
|
1036
|
+
// before `agent.stream(...)` appends them, so a later `rewindSession`
|
|
1037
|
+
// can splice history back to exactly this point.
|
|
1038
|
+
if (turnMessageId) {
|
|
1039
|
+
recordTurnBoundary(rec.agent, turnMessageId, rec.agent.messages.length);
|
|
1040
|
+
}
|
|
972
1041
|
const signals = [turnAbort.signal];
|
|
973
1042
|
if (this.#connectionSignal) {
|
|
974
1043
|
signals.push(this.#connectionSignal);
|
|
@@ -1001,7 +1070,18 @@ export class HoomanAcpAgent {
|
|
|
1001
1070
|
// live output with a JSON result blob. The structured result
|
|
1002
1071
|
// still travels to the model via `rawOutput`.
|
|
1003
1072
|
const terminalId = rec.terminalByToolCall.get(ev.toolUse.toolUseId);
|
|
1004
|
-
|
|
1073
|
+
// Keep terminalByToolCall for background jobs so live polling
|
|
1074
|
+
// can continue; only drop the mapping for foreground shells.
|
|
1075
|
+
const bgJob = extractBackgroundShellFromResult(ev.result);
|
|
1076
|
+
if (!bgJob) {
|
|
1077
|
+
rec.terminalByToolCall.delete(ev.toolUse.toolUseId);
|
|
1078
|
+
}
|
|
1079
|
+
else if (terminalId) {
|
|
1080
|
+
rec.shellJobs.set(bgJob.jobId, {
|
|
1081
|
+
terminalId,
|
|
1082
|
+
toolCallId: ev.toolUse.toolUseId,
|
|
1083
|
+
});
|
|
1084
|
+
}
|
|
1005
1085
|
const content = terminalId !== undefined
|
|
1006
1086
|
? [{ type: "terminal", terminalId }]
|
|
1007
1087
|
: (diff ?? toolResultToAcpContent(ev.result));
|
|
@@ -1012,14 +1092,27 @@ export class HoomanAcpAgent {
|
|
|
1012
1092
|
rawOutput: ev.result.toJSON(),
|
|
1013
1093
|
content,
|
|
1014
1094
|
...(locations ? { locations } : {}),
|
|
1095
|
+
...(bgJob
|
|
1096
|
+
? {
|
|
1097
|
+
_meta: {
|
|
1098
|
+
"hoomanjs/shell_job": {
|
|
1099
|
+
event: "started",
|
|
1100
|
+
job_id: bgJob.jobId,
|
|
1101
|
+
description: bgJob.description,
|
|
1102
|
+
status: bgJob.jobStatus ?? "running",
|
|
1103
|
+
terminal_id: terminalId,
|
|
1104
|
+
tool_call_id: ev.toolUse.toolUseId,
|
|
1105
|
+
},
|
|
1106
|
+
},
|
|
1107
|
+
}
|
|
1108
|
+
: {}),
|
|
1015
1109
|
});
|
|
1016
1110
|
if (ev.toolUse.name === UPDATE_TODOS_TOOL_NAME &&
|
|
1017
1111
|
ev.result.status === "success") {
|
|
1018
1112
|
await this.#sendPlanUpdate(client, params.sessionId, rec);
|
|
1019
1113
|
}
|
|
1020
1114
|
if (ev.result.status === "success" &&
|
|
1021
|
-
|
|
1022
|
-
ev.toolUse.name === EXIT_PLAN_MODE_TOOL)) {
|
|
1115
|
+
ev.toolUse.name === SWITCH_MODE_TOOL) {
|
|
1023
1116
|
await this.#syncCurrentMode(client, params.sessionId, rec);
|
|
1024
1117
|
}
|
|
1025
1118
|
}
|
|
@@ -1135,8 +1228,8 @@ export class HoomanAcpAgent {
|
|
|
1135
1228
|
});
|
|
1136
1229
|
}
|
|
1137
1230
|
/**
|
|
1138
|
-
* Reflect an agent-driven mode change (
|
|
1139
|
-
* `
|
|
1231
|
+
* Reflect an agent-driven mode change (`switch_mode`) to the client via
|
|
1232
|
+
* `current_mode_update` and persist it.
|
|
1140
1233
|
*/
|
|
1141
1234
|
async #syncCurrentMode(client, sessionId, rec) {
|
|
1142
1235
|
const modeId = resolveSessionMode(getModeState(rec.agent).mode);
|
|
@@ -1379,8 +1472,10 @@ export class HoomanAcpAgent {
|
|
|
1379
1472
|
this.#registerTextFsBackend(agent, client, sessionId);
|
|
1380
1473
|
this.#registerTerminalBackend(agent, client, sessionId);
|
|
1381
1474
|
setAskUserBackend(agent, createAcpAskUserBackend(client, sessionId));
|
|
1475
|
+
setBrowserPreviewBackend(agent, createAcpBrowserPreviewBackend(client, sessionId));
|
|
1382
1476
|
const activeLlm = config.llm;
|
|
1383
1477
|
const metadata = await resolveLlmMetadata(activeLlm.metadata, activeLlm.llmOptions.model, activeLlm.provider, configuredLlmContext(activeLlm)).catch(() => null);
|
|
1478
|
+
setLlmModality(agent, metadata?.modality);
|
|
1384
1479
|
return {
|
|
1385
1480
|
cwd,
|
|
1386
1481
|
agent,
|
|
@@ -1393,6 +1488,8 @@ export class HoomanAcpAgent {
|
|
|
1393
1488
|
streamingToolInputJson: new Map(),
|
|
1394
1489
|
lastStreamToolUseId: null,
|
|
1395
1490
|
terminalByToolCall: new Map(),
|
|
1491
|
+
shellJobs: new Map(),
|
|
1492
|
+
shellJobUnsub: null,
|
|
1396
1493
|
currentAssistantMessageId: null,
|
|
1397
1494
|
pendingModeReapply: false,
|
|
1398
1495
|
pendingModelRebuild: false,
|
|
@@ -1447,7 +1544,134 @@ export class HoomanAcpAgent {
|
|
|
1447
1544
|
}
|
|
1448
1545
|
setTerminalBackend(agent, {
|
|
1449
1546
|
run: (request) => this.#runClientTerminal(client, sessionId, request),
|
|
1547
|
+
spawn: (request) => this.#spawnClientTerminal(client, sessionId, request),
|
|
1548
|
+
readOutput: (terminalId) => this.#readClientTerminal(client, sessionId, terminalId),
|
|
1549
|
+
kill: (terminalId) => this.#killClientTerminal(client, sessionId, terminalId),
|
|
1550
|
+
});
|
|
1551
|
+
}
|
|
1552
|
+
/** Call after the SessionRecord is stored in `#sessions`. */
|
|
1553
|
+
#subscribeShellJobs(agent, client, sessionId) {
|
|
1554
|
+
const record = this.#sessions.get(sessionId);
|
|
1555
|
+
if (!record) {
|
|
1556
|
+
return;
|
|
1557
|
+
}
|
|
1558
|
+
record.shellJobUnsub?.();
|
|
1559
|
+
const manager = getShellJobManager(agent);
|
|
1560
|
+
record.shellJobUnsub = manager.on((event) => {
|
|
1561
|
+
void this.#onShellJobEvent(client, sessionId, event);
|
|
1562
|
+
});
|
|
1563
|
+
}
|
|
1564
|
+
async #onShellJobEvent(client, sessionId, event) {
|
|
1565
|
+
if (event.type !== "completed" &&
|
|
1566
|
+
event.type !== "stopped" &&
|
|
1567
|
+
event.type !== "failed") {
|
|
1568
|
+
return;
|
|
1569
|
+
}
|
|
1570
|
+
const job = event.job;
|
|
1571
|
+
const meta = {
|
|
1572
|
+
"hoomanjs/shell_job": {
|
|
1573
|
+
event: event.type,
|
|
1574
|
+
job_id: job.id,
|
|
1575
|
+
description: job.description,
|
|
1576
|
+
status: job.status,
|
|
1577
|
+
ready: job.ready,
|
|
1578
|
+
exit_code: job.exitCode,
|
|
1579
|
+
signal: job.signal,
|
|
1580
|
+
terminal_id: job.terminalId,
|
|
1581
|
+
tool_call_id: job.toolUseId,
|
|
1582
|
+
},
|
|
1583
|
+
};
|
|
1584
|
+
// Meta-only update for the jobs bar — empty text so nothing lands in the
|
|
1585
|
+
// transcript. Fire-and-forget release: awaiting a nested terminal/* RPC
|
|
1586
|
+
// from inside stop_shell_job deadlocks the ACP connection.
|
|
1587
|
+
void this.#sendUpdate(client, sessionId, {
|
|
1588
|
+
sessionUpdate: "agent_message_chunk",
|
|
1589
|
+
content: {
|
|
1590
|
+
type: "text",
|
|
1591
|
+
text: "",
|
|
1592
|
+
},
|
|
1593
|
+
_meta: meta,
|
|
1594
|
+
}).catch(() => undefined);
|
|
1595
|
+
const record = this.#sessions.get(sessionId);
|
|
1596
|
+
const hosted = record?.shellJobs.get(job.id);
|
|
1597
|
+
if (hosted) {
|
|
1598
|
+
record?.shellJobs.delete(job.id);
|
|
1599
|
+
void client
|
|
1600
|
+
.request(methods.client.terminal.release, {
|
|
1601
|
+
sessionId,
|
|
1602
|
+
terminalId: hosted.terminalId,
|
|
1603
|
+
})
|
|
1604
|
+
.catch(() => undefined);
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
async #spawnClientTerminal(client, sessionId, request) {
|
|
1608
|
+
const created = await client.request(methods.client.terminal.create, {
|
|
1609
|
+
sessionId,
|
|
1610
|
+
command: request.command,
|
|
1611
|
+
args: request.args,
|
|
1612
|
+
cwd: request.cwd,
|
|
1613
|
+
...(request.outputByteLimit !== undefined
|
|
1614
|
+
? { outputByteLimit: request.outputByteLimit }
|
|
1615
|
+
: {}),
|
|
1616
|
+
}, { cancellationSignal: request.cancelSignal });
|
|
1617
|
+
const terminalId = created.terminalId;
|
|
1618
|
+
const record = this.#sessions.get(sessionId);
|
|
1619
|
+
if (request.jobId && record) {
|
|
1620
|
+
record.shellJobs.set(request.jobId, {
|
|
1621
|
+
terminalId,
|
|
1622
|
+
toolCallId: request.toolUseId,
|
|
1623
|
+
});
|
|
1624
|
+
}
|
|
1625
|
+
if (request.toolUseId) {
|
|
1626
|
+
record?.terminalByToolCall.set(request.toolUseId, terminalId);
|
|
1627
|
+
await this.#sendUpdate(client, sessionId, {
|
|
1628
|
+
sessionUpdate: "tool_call_update",
|
|
1629
|
+
toolCallId: request.toolUseId,
|
|
1630
|
+
status: "in_progress",
|
|
1631
|
+
content: [{ type: "terminal", terminalId }],
|
|
1632
|
+
});
|
|
1633
|
+
}
|
|
1634
|
+
return { terminalId };
|
|
1635
|
+
}
|
|
1636
|
+
async #readClientTerminal(client, sessionId, terminalId) {
|
|
1637
|
+
const output = await client.request(methods.client.terminal.output, {
|
|
1638
|
+
sessionId,
|
|
1639
|
+
terminalId,
|
|
1450
1640
|
});
|
|
1641
|
+
return {
|
|
1642
|
+
output: output.output,
|
|
1643
|
+
truncated: output.truncated,
|
|
1644
|
+
exitCode: output.exitStatus?.exitCode ?? null,
|
|
1645
|
+
signal: output.exitStatus?.signal ?? null,
|
|
1646
|
+
};
|
|
1647
|
+
}
|
|
1648
|
+
async #killClientTerminal(client, sessionId, terminalId) {
|
|
1649
|
+
await client
|
|
1650
|
+
.request(methods.client.terminal.kill, { sessionId, terminalId })
|
|
1651
|
+
.catch(() => undefined);
|
|
1652
|
+
}
|
|
1653
|
+
async #teardownShellJobs(sessionId, record) {
|
|
1654
|
+
record.shellJobUnsub?.();
|
|
1655
|
+
record.shellJobUnsub = null;
|
|
1656
|
+
const client = this.#client;
|
|
1657
|
+
for (const [jobId, hosted] of record.shellJobs) {
|
|
1658
|
+
if (client) {
|
|
1659
|
+
await client
|
|
1660
|
+
.request(methods.client.terminal.kill, {
|
|
1661
|
+
sessionId,
|
|
1662
|
+
terminalId: hosted.terminalId,
|
|
1663
|
+
})
|
|
1664
|
+
.catch(() => undefined);
|
|
1665
|
+
await client
|
|
1666
|
+
.request(methods.client.terminal.release, {
|
|
1667
|
+
sessionId,
|
|
1668
|
+
terminalId: hosted.terminalId,
|
|
1669
|
+
})
|
|
1670
|
+
.catch(() => undefined);
|
|
1671
|
+
}
|
|
1672
|
+
record.shellJobs.delete(jobId);
|
|
1673
|
+
}
|
|
1674
|
+
await clearShellJobManager(record.agent).catch(() => undefined);
|
|
1451
1675
|
}
|
|
1452
1676
|
async #runClientTerminal(client, sessionId, request) {
|
|
1453
1677
|
const created = await client.request(methods.client.terminal.create, {
|
|
@@ -1545,10 +1769,11 @@ export class HoomanAcpAgent {
|
|
|
1545
1769
|
}
|
|
1546
1770
|
}
|
|
1547
1771
|
async #disposeAll() {
|
|
1548
|
-
const
|
|
1772
|
+
const entries = [...this.#sessions.entries()];
|
|
1549
1773
|
this.#sessions.clear();
|
|
1550
|
-
for (const record of
|
|
1774
|
+
for (const [sessionId, record] of entries) {
|
|
1551
1775
|
record.turnAbort?.abort();
|
|
1776
|
+
await this.#teardownShellJobs(sessionId, record);
|
|
1552
1777
|
await record.mcpDisconnect();
|
|
1553
1778
|
}
|
|
1554
1779
|
}
|
|
@@ -1565,6 +1790,8 @@ export function createAcpApp(agent) {
|
|
|
1565
1790
|
.onRequest(methods.agent.session.list, (ctx) => agent.listSessions(ctx.params))
|
|
1566
1791
|
.onRequest(methods.agent.session.delete, (ctx) => agent.deleteSession(ctx.params))
|
|
1567
1792
|
.onRequest(methods.agent.session.fork, (ctx) => agent.forkSession(ctx.params, ctx.client))
|
|
1793
|
+
.onRequest("_hoomanjs/rewind_session", (params) => params, (ctx) => agent.rewindSession(ctx.params))
|
|
1794
|
+
.onRequest("_hoomanjs/stop_shell_job", (params) => params, (ctx) => agent.stopShellJob(ctx.params))
|
|
1568
1795
|
.onRequest(methods.agent.session.setMode, (ctx) => agent.setSessionMode(ctx.params, ctx.client))
|
|
1569
1796
|
.onRequest(methods.agent.session.setConfigOption, (ctx) => agent.setSessionConfigOption(ctx.params, ctx.client))
|
|
1570
1797
|
.onRequest(methods.agent.session.prompt, (ctx) => agent.prompt(ctx.params))
|
|
@@ -1577,4 +1804,66 @@ export async function runAcpStdio() {
|
|
|
1577
1804
|
const connection = createAcpApp(new HoomanAcpAgent(identity)).connect(stream);
|
|
1578
1805
|
await connection.closed;
|
|
1579
1806
|
}
|
|
1807
|
+
/**
|
|
1808
|
+
* Pull a background shell job payload out of a Strands tool result.
|
|
1809
|
+
* The tool returns `{ status: "background", job_id, ... }` which the SDK wraps
|
|
1810
|
+
* as a ToolResultBlock with a json content block.
|
|
1811
|
+
*/
|
|
1812
|
+
function extractBackgroundShellFromResult(result) {
|
|
1813
|
+
const fromValue = (value) => {
|
|
1814
|
+
if (!value || typeof value !== "object") {
|
|
1815
|
+
return null;
|
|
1816
|
+
}
|
|
1817
|
+
const record = value;
|
|
1818
|
+
if (record.status === "background" && typeof record.job_id === "string") {
|
|
1819
|
+
return {
|
|
1820
|
+
jobId: record.job_id,
|
|
1821
|
+
description: typeof record.description === "string"
|
|
1822
|
+
? record.description
|
|
1823
|
+
: undefined,
|
|
1824
|
+
jobStatus: typeof record.job_status === "string" ? record.job_status : undefined,
|
|
1825
|
+
};
|
|
1826
|
+
}
|
|
1827
|
+
return null;
|
|
1828
|
+
};
|
|
1829
|
+
if (Array.isArray(result.content)) {
|
|
1830
|
+
for (const block of result.content) {
|
|
1831
|
+
if (!block || typeof block !== "object") {
|
|
1832
|
+
continue;
|
|
1833
|
+
}
|
|
1834
|
+
const json = block.json;
|
|
1835
|
+
const nested = fromValue(json ?? block);
|
|
1836
|
+
if (nested) {
|
|
1837
|
+
return nested;
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
try {
|
|
1842
|
+
const serialized = result.toJSON?.();
|
|
1843
|
+
if (serialized && typeof serialized === "object") {
|
|
1844
|
+
const wrapped = serialized;
|
|
1845
|
+
const content = wrapped.toolResult?.content ?? wrapped.content;
|
|
1846
|
+
if (Array.isArray(content)) {
|
|
1847
|
+
for (const block of content) {
|
|
1848
|
+
if (!block || typeof block !== "object") {
|
|
1849
|
+
continue;
|
|
1850
|
+
}
|
|
1851
|
+
const json = block.json;
|
|
1852
|
+
const nested = fromValue(json ?? block);
|
|
1853
|
+
if (nested) {
|
|
1854
|
+
return nested;
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
const direct = fromValue(serialized);
|
|
1859
|
+
if (direct) {
|
|
1860
|
+
return direct;
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
}
|
|
1864
|
+
catch {
|
|
1865
|
+
// ignore serialization errors
|
|
1866
|
+
}
|
|
1867
|
+
return null;
|
|
1868
|
+
}
|
|
1580
1869
|
//# sourceMappingURL=acp-agent.js.map
|