@vascend/talos 0.1.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 +202 -0
- package/dist/backend/asset-events.d.ts +31 -0
- package/dist/backend/asset-events.js +149 -0
- package/dist/backend/assets.d.ts +31 -0
- package/dist/backend/assets.js +210 -0
- package/dist/backend/auth.d.ts +18 -0
- package/dist/backend/auth.js +59 -0
- package/dist/backend/config.d.ts +14 -0
- package/dist/backend/config.js +41 -0
- package/dist/backend/conversations.d.ts +21 -0
- package/dist/backend/conversations.js +141 -0
- package/dist/backend/crypto.d.ts +9 -0
- package/dist/backend/crypto.js +68 -0
- package/dist/backend/engine.d.ts +13 -0
- package/dist/backend/engine.js +78 -0
- package/dist/backend/http.d.ts +25 -0
- package/dist/backend/http.js +112 -0
- package/dist/backend/index.d.ts +1 -0
- package/dist/backend/index.js +24 -0
- package/dist/backend/routes.d.ts +14 -0
- package/dist/backend/routes.js +169 -0
- package/dist/backend/sdk.d.ts +12 -0
- package/dist/backend/sdk.js +11 -0
- package/dist/backend/server.d.ts +12 -0
- package/dist/backend/server.js +91 -0
- package/dist/backend/temp-image-store.d.ts +46 -0
- package/dist/backend/temp-image-store.js +197 -0
- package/dist/backend/types.d.ts +103 -0
- package/dist/backend/types.js +29 -0
- package/dist/backend/users.d.ts +13 -0
- package/dist/backend/users.js +76 -0
- package/dist/backend/ws-handler.d.ts +14 -0
- package/dist/backend/ws-handler.js +72 -0
- package/dist/backend/ws.d.ts +19 -0
- package/dist/backend/ws.js +146 -0
- package/dist/core/agent.d.ts +56 -0
- package/dist/core/agent.js +1783 -0
- package/dist/core/background.d.ts +45 -0
- package/dist/core/background.js +140 -0
- package/dist/core/bootstrap.d.ts +45 -0
- package/dist/core/bootstrap.js +294 -0
- package/dist/core/cli-args.d.ts +41 -0
- package/dist/core/cli-args.js +282 -0
- package/dist/core/collapsible-output.d.ts +38 -0
- package/dist/core/collapsible-output.js +143 -0
- package/dist/core/compaction-checkpoint.d.ts +9 -0
- package/dist/core/compaction-checkpoint.js +58 -0
- package/dist/core/compaction.d.ts +42 -0
- package/dist/core/compaction.js +270 -0
- package/dist/core/config.d.ts +49 -0
- package/dist/core/config.js +417 -0
- package/dist/core/context-ledger.d.ts +99 -0
- package/dist/core/context-ledger.js +222 -0
- package/dist/core/context-policy.d.ts +17 -0
- package/dist/core/context-policy.js +81 -0
- package/dist/core/continuation-review.d.ts +23 -0
- package/dist/core/continuation-review.js +64 -0
- package/dist/core/crash-report.d.ts +3 -0
- package/dist/core/crash-report.js +27 -0
- package/dist/core/credentials.d.ts +11 -0
- package/dist/core/credentials.js +183 -0
- package/dist/core/doctor.d.ts +24 -0
- package/dist/core/doctor.js +125 -0
- package/dist/core/effort.d.ts +5 -0
- package/dist/core/effort.js +42 -0
- package/dist/core/env-paths.d.ts +3 -0
- package/dist/core/env-paths.js +38 -0
- package/dist/core/execution-guidance.d.ts +9 -0
- package/dist/core/execution-guidance.js +73 -0
- package/dist/core/execution-target.d.ts +41 -0
- package/dist/core/execution-target.js +69 -0
- package/dist/core/file-coordination.d.ts +66 -0
- package/dist/core/file-coordination.js +176 -0
- package/dist/core/file-lease-store.d.ts +14 -0
- package/dist/core/file-lease-store.js +89 -0
- package/dist/core/image-limits.d.ts +26 -0
- package/dist/core/image-limits.js +205 -0
- package/dist/core/interruptible-completion.d.ts +3 -0
- package/dist/core/interruptible-completion.js +42 -0
- package/dist/core/kingdoms-mode-state.d.ts +24 -0
- package/dist/core/kingdoms-mode-state.js +139 -0
- package/dist/core/licenza.d.ts +38 -0
- package/dist/core/licenza.js +125 -0
- package/dist/core/model-limits.d.ts +2 -0
- package/dist/core/model-limits.js +36 -0
- package/dist/core/output-lifecycle.d.ts +44 -0
- package/dist/core/output-lifecycle.js +190 -0
- package/dist/core/package-update.d.ts +15 -0
- package/dist/core/package-update.js +121 -0
- package/dist/core/permission-queue.d.ts +2 -0
- package/dist/core/permission-queue.js +20 -0
- package/dist/core/prompt-attachment.d.ts +21 -0
- package/dist/core/prompt-attachment.js +123 -0
- package/dist/core/request-plan.d.ts +16 -0
- package/dist/core/request-plan.js +36 -0
- package/dist/core/run-timing.d.ts +17 -0
- package/dist/core/run-timing.js +123 -0
- package/dist/core/self-update.d.ts +17 -0
- package/dist/core/self-update.js +54 -0
- package/dist/core/session-refs.d.ts +27 -0
- package/dist/core/session-refs.js +126 -0
- package/dist/core/session-storage.d.ts +4 -0
- package/dist/core/session-storage.js +48 -0
- package/dist/core/session-title.d.ts +1 -0
- package/dist/core/session-title.js +21 -0
- package/dist/core/session-usage.d.ts +17 -0
- package/dist/core/session-usage.js +74 -0
- package/dist/core/session.d.ts +58 -0
- package/dist/core/session.js +296 -0
- package/dist/core/settings.d.ts +17 -0
- package/dist/core/settings.js +107 -0
- package/dist/core/storage-retention.d.ts +21 -0
- package/dist/core/storage-retention.js +227 -0
- package/dist/core/text-sanitize.d.ts +1 -0
- package/dist/core/text-sanitize.js +35 -0
- package/dist/core/tool-artifacts.d.ts +6 -0
- package/dist/core/tool-artifacts.js +51 -0
- package/dist/core/tool-compress.d.ts +8 -0
- package/dist/core/tool-compress.js +111 -0
- package/dist/core/tool-executor.d.ts +16 -0
- package/dist/core/tool-executor.js +97 -0
- package/dist/core/tool-result-index.d.ts +52 -0
- package/dist/core/tool-result-index.js +327 -0
- package/dist/core/tool-result-store.d.ts +38 -0
- package/dist/core/tool-result-store.js +190 -0
- package/dist/core/tool-scheduler.d.ts +16 -0
- package/dist/core/tool-scheduler.js +35 -0
- package/dist/core/trust.d.ts +21 -0
- package/dist/core/trust.js +95 -0
- package/dist/core/types.d.ts +402 -0
- package/dist/core/types.js +1 -0
- package/dist/core/update-check.d.ts +26 -0
- package/dist/core/update-check.js +89 -0
- package/dist/core/update-process.d.ts +10 -0
- package/dist/core/update-process.js +31 -0
- package/dist/core/user-inbox.d.ts +23 -0
- package/dist/core/user-inbox.js +56 -0
- package/dist/core/user-input.d.ts +10 -0
- package/dist/core/user-input.js +35 -0
- package/dist/core/version.d.ts +1 -0
- package/dist/core/version.js +10 -0
- package/dist/core/vibe-modes.d.ts +38 -0
- package/dist/core/vibe-modes.js +383 -0
- package/dist/core/workspace-roots.d.ts +13 -0
- package/dist/core/workspace-roots.js +91 -0
- package/dist/core/workspace-sessions.d.ts +51 -0
- package/dist/core/workspace-sessions.js +243 -0
- package/dist/cowork/client.d.ts +29 -0
- package/dist/cowork/client.js +49 -0
- package/dist/cowork/engine-bridge.d.ts +22 -0
- package/dist/cowork/engine-bridge.js +98 -0
- package/dist/cowork/index.d.ts +11 -0
- package/dist/cowork/index.js +16 -0
- package/dist/cowork/ipc.d.ts +97 -0
- package/dist/cowork/ipc.js +96 -0
- package/dist/cowork/manager.d.ts +66 -0
- package/dist/cowork/manager.js +325 -0
- package/dist/cowork/store.d.ts +23 -0
- package/dist/cowork/store.js +182 -0
- package/dist/cowork/sync.d.ts +20 -0
- package/dist/cowork/sync.js +164 -0
- package/dist/cowork/types.d.ts +78 -0
- package/dist/cowork/types.js +21 -0
- package/dist/extensions/ext-tools.d.ts +3 -0
- package/dist/extensions/ext-tools.js +73 -0
- package/dist/extensions/loader.d.ts +91 -0
- package/dist/extensions/loader.js +474 -0
- package/dist/extensions/settings.d.ts +20 -0
- package/dist/extensions/settings.js +86 -0
- package/dist/extensions/types.d.ts +219 -0
- package/dist/extensions/types.js +1 -0
- package/dist/horizon/async-queue.d.ts +9 -0
- package/dist/horizon/async-queue.js +46 -0
- package/dist/horizon/engine.d.ts +85 -0
- package/dist/horizon/engine.js +603 -0
- package/dist/horizon/index.d.ts +4 -0
- package/dist/horizon/index.js +2 -0
- package/dist/horizon/main-team.d.ts +163 -0
- package/dist/horizon/main-team.js +774 -0
- package/dist/horizon/types.d.ts +233 -0
- package/dist/horizon/types.js +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +233 -0
- package/dist/mcp/protocol.d.ts +81 -0
- package/dist/mcp/protocol.js +122 -0
- package/dist/package.json +1 -0
- package/dist/packages/packages.d.ts +12 -0
- package/dist/packages/packages.js +323 -0
- package/dist/prompts/templates.d.ts +13 -0
- package/dist/prompts/templates.js +139 -0
- package/dist/providers/anthropic-oauth.d.ts +13 -0
- package/dist/providers/anthropic-oauth.js +124 -0
- package/dist/providers/anthropic.d.ts +27 -0
- package/dist/providers/anthropic.js +526 -0
- package/dist/providers/catalog.d.ts +15 -0
- package/dist/providers/catalog.js +166 -0
- package/dist/providers/effort.d.ts +12 -0
- package/dist/providers/effort.js +102 -0
- package/dist/providers/model-catalog.d.ts +43 -0
- package/dist/providers/model-catalog.js +70 -0
- package/dist/providers/model-effort.d.ts +5 -0
- package/dist/providers/model-effort.js +43 -0
- package/dist/providers/model-registry.d.ts +39 -0
- package/dist/providers/model-registry.js +142 -0
- package/dist/providers/models-dev.d.ts +9 -0
- package/dist/providers/models-dev.js +97 -0
- package/dist/providers/oauth-callback-server.d.ts +28 -0
- package/dist/providers/oauth-callback-server.js +184 -0
- package/dist/providers/oauth-orchestrator.d.ts +58 -0
- package/dist/providers/oauth-orchestrator.js +159 -0
- package/dist/providers/oauth-store.d.ts +12 -0
- package/dist/providers/oauth-store.js +139 -0
- package/dist/providers/open-browser.d.ts +20 -0
- package/dist/providers/open-browser.js +92 -0
- package/dist/providers/openai-compat.d.ts +14 -0
- package/dist/providers/openai-compat.js +523 -0
- package/dist/providers/openai-oauth.d.ts +15 -0
- package/dist/providers/openai-oauth.js +382 -0
- package/dist/providers/openrouter-auth.d.ts +73 -0
- package/dist/providers/openrouter-auth.js +321 -0
- package/dist/providers/openrouter-manual-fallback.d.ts +25 -0
- package/dist/providers/openrouter-manual-fallback.js +161 -0
- package/dist/providers/openrouter.d.ts +15 -0
- package/dist/providers/openrouter.js +107 -0
- package/dist/providers/plan-limits.d.ts +6 -0
- package/dist/providers/plan-limits.js +175 -0
- package/dist/providers/provider-reset.d.ts +4 -0
- package/dist/providers/provider-reset.js +83 -0
- package/dist/providers/quota-limits.d.ts +4 -0
- package/dist/providers/quota-limits.js +33 -0
- package/dist/providers/registry.d.ts +33 -0
- package/dist/providers/registry.js +213 -0
- package/dist/providers/retry.d.ts +37 -0
- package/dist/providers/retry.js +347 -0
- package/dist/rpc/server.d.ts +23 -0
- package/dist/rpc/server.js +222 -0
- package/dist/sdk.d.ts +67 -0
- package/dist/sdk.js +64 -0
- package/dist/skills/skills.d.ts +17 -0
- package/dist/skills/skills.js +155 -0
- package/dist/text-sanitize.js +28 -0
- package/dist/tools/ask-user.d.ts +2 -0
- package/dist/tools/ask-user.js +60 -0
- package/dist/tools/builtin.d.ts +48 -0
- package/dist/tools/builtin.js +2494 -0
- package/dist/tools/capabilities.d.ts +5 -0
- package/dist/tools/capabilities.js +55 -0
- package/dist/tools/computer-capture.d.ts +2 -0
- package/dist/tools/computer-capture.js +91 -0
- package/dist/tools/computer-posix.d.ts +5 -0
- package/dist/tools/computer-posix.js +136 -0
- package/dist/tools/computer-use.d.ts +14 -0
- package/dist/tools/computer-use.js +108 -0
- package/dist/tools/discovery.d.ts +12 -0
- package/dist/tools/discovery.js +205 -0
- package/dist/tools/execute.d.ts +2 -0
- package/dist/tools/execute.js +73 -0
- package/dist/tools/normalize-input.d.ts +17 -0
- package/dist/tools/normalize-input.js +174 -0
- package/dist/tools/output-artifact.d.ts +3 -0
- package/dist/tools/output-artifact.js +80 -0
- package/dist/tools/pagination.d.ts +15 -0
- package/dist/tools/pagination.js +93 -0
- package/dist/tools/plan-status.d.ts +2 -0
- package/dist/tools/plan-status.js +109 -0
- package/dist/tools/program-input.d.ts +3 -0
- package/dist/tools/program-input.js +19 -0
- package/dist/tools/program.d.ts +3 -0
- package/dist/tools/program.js +567 -0
- package/dist/tools/protocol-catalog.d.ts +12 -0
- package/dist/tools/protocol-catalog.js +46 -0
- package/dist/tools/ramification-tools.d.ts +12 -0
- package/dist/tools/ramification-tools.js +528 -0
- package/dist/tools/regex-compat.d.ts +9 -0
- package/dist/tools/regex-compat.js +96 -0
- package/dist/tools/registry.d.ts +51 -0
- package/dist/tools/registry.js +185 -0
- package/dist/tools/resolve.d.ts +2 -0
- package/dist/tools/resolve.js +107 -0
- package/dist/tools/shell-env.d.ts +2 -0
- package/dist/tools/shell-env.js +7 -0
- package/dist/tools/team-input.d.ts +3 -0
- package/dist/tools/team-input.js +129 -0
- package/dist/tools/team-tools.d.ts +7 -0
- package/dist/tools/team-tools.js +348 -0
- package/dist/tools/workspace-sessions.d.ts +2 -0
- package/dist/tools/workspace-sessions.js +35 -0
- package/dist/tui/account-entry.d.ts +1 -0
- package/dist/tui/account-entry.js +93 -0
- package/dist/tui/attachment-highlight.d.ts +1 -0
- package/dist/tui/attachment-highlight.js +24 -0
- package/dist/tui/attachment-refs.d.ts +2 -0
- package/dist/tui/attachment-refs.js +3 -0
- package/dist/tui/bottom-input.d.ts +219 -0
- package/dist/tui/bottom-input.js +1958 -0
- package/dist/tui/branding.d.ts +107 -0
- package/dist/tui/branding.js +750 -0
- package/dist/tui/clipboard-image.d.ts +10 -0
- package/dist/tui/clipboard-image.js +163 -0
- package/dist/tui/clipboard-text.d.ts +9 -0
- package/dist/tui/clipboard-text.js +51 -0
- package/dist/tui/clipboard-windows.d.ts +8 -0
- package/dist/tui/clipboard-windows.js +84 -0
- package/dist/tui/collapsible-command.d.ts +15 -0
- package/dist/tui/collapsible-command.js +48 -0
- package/dist/tui/command-feedback.d.ts +10 -0
- package/dist/tui/command-feedback.js +46 -0
- package/dist/tui/command-output-registry.d.ts +28 -0
- package/dist/tui/command-output-registry.js +103 -0
- package/dist/tui/command-transcript.d.ts +12 -0
- package/dist/tui/command-transcript.js +90 -0
- package/dist/tui/commands.d.ts +20 -0
- package/dist/tui/commands.js +131 -0
- package/dist/tui/context-bar.d.ts +4 -0
- package/dist/tui/context-bar.js +74 -0
- package/dist/tui/context-meter.d.ts +25 -0
- package/dist/tui/context-meter.js +81 -0
- package/dist/tui/cost-binding.d.ts +8 -0
- package/dist/tui/cost-binding.js +43 -0
- package/dist/tui/cost-tracker.d.ts +49 -0
- package/dist/tui/cost-tracker.js +122 -0
- package/dist/tui/diff.d.ts +9 -0
- package/dist/tui/diff.js +119 -0
- package/dist/tui/i18n-catalog.d.ts +5 -0
- package/dist/tui/i18n-catalog.js +184 -0
- package/dist/tui/i18n.d.ts +6 -0
- package/dist/tui/i18n.js +10 -0
- package/dist/tui/image-attachments.d.ts +46 -0
- package/dist/tui/image-attachments.js +167 -0
- package/dist/tui/images.d.ts +12 -0
- package/dist/tui/images.js +87 -0
- package/dist/tui/intro.d.ts +13 -0
- package/dist/tui/intro.js +109 -0
- package/dist/tui/language-preference.d.ts +6 -0
- package/dist/tui/language-preference.js +24 -0
- package/dist/tui/live-output.d.ts +2 -0
- package/dist/tui/live-output.js +18 -0
- package/dist/tui/locales.d.ts +19 -0
- package/dist/tui/locales.js +22 -0
- package/dist/tui/login-menu.d.ts +17 -0
- package/dist/tui/login-menu.js +58 -0
- package/dist/tui/logo.d.ts +8 -0
- package/dist/tui/logo.js +305 -0
- package/dist/tui/markdown-inline.d.ts +3 -0
- package/dist/tui/markdown-inline.js +99 -0
- package/dist/tui/markdown-table.d.ts +4 -0
- package/dist/tui/markdown-table.js +63 -0
- package/dist/tui/markdown.d.ts +11 -0
- package/dist/tui/markdown.js +257 -0
- package/dist/tui/mcp-transcript.d.ts +7 -0
- package/dist/tui/mcp-transcript.js +40 -0
- package/dist/tui/model-details.d.ts +2 -0
- package/dist/tui/model-details.js +21 -0
- package/dist/tui/model-selection.d.ts +7 -0
- package/dist/tui/model-selection.js +41 -0
- package/dist/tui/native-scrollback.d.ts +27 -0
- package/dist/tui/native-scrollback.js +134 -0
- package/dist/tui/onboarding.d.ts +72 -0
- package/dist/tui/onboarding.js +207 -0
- package/dist/tui/paste-collapse.d.ts +39 -0
- package/dist/tui/paste-collapse.js +117 -0
- package/dist/tui/perm-mode.d.ts +8 -0
- package/dist/tui/perm-mode.js +41 -0
- package/dist/tui/prompt-queue-store.d.ts +26 -0
- package/dist/tui/prompt-queue-store.js +87 -0
- package/dist/tui/prompt-queue.d.ts +47 -0
- package/dist/tui/prompt-queue.js +187 -0
- package/dist/tui/provider-menu.d.ts +33 -0
- package/dist/tui/provider-menu.js +175 -0
- package/dist/tui/question.d.ts +24 -0
- package/dist/tui/question.js +32 -0
- package/dist/tui/queue-screen.d.ts +25 -0
- package/dist/tui/queue-screen.js +152 -0
- package/dist/tui/queue-team.d.ts +3 -0
- package/dist/tui/queue-team.js +28 -0
- package/dist/tui/queued-questions.d.ts +20 -0
- package/dist/tui/queued-questions.js +163 -0
- package/dist/tui/quick-help.d.ts +1 -0
- package/dist/tui/quick-help.js +53 -0
- package/dist/tui/repl.d.ts +78 -0
- package/dist/tui/repl.js +4130 -0
- package/dist/tui/restore-queued-input.d.ts +3 -0
- package/dist/tui/restore-queued-input.js +20 -0
- package/dist/tui/review-detail.d.ts +6 -0
- package/dist/tui/review-detail.js +56 -0
- package/dist/tui/review-files.d.ts +3 -0
- package/dist/tui/review-files.js +22 -0
- package/dist/tui/review-render.d.ts +22 -0
- package/dist/tui/review-render.js +98 -0
- package/dist/tui/review-screen.d.ts +38 -0
- package/dist/tui/review-screen.js +358 -0
- package/dist/tui/review-store.d.ts +60 -0
- package/dist/tui/review-store.js +270 -0
- package/dist/tui/review-team.d.ts +2 -0
- package/dist/tui/review-team.js +27 -0
- package/dist/tui/selector-mouse.d.ts +26 -0
- package/dist/tui/selector-mouse.js +65 -0
- package/dist/tui/selector.d.ts +51 -0
- package/dist/tui/selector.js +299 -0
- package/dist/tui/session-replay.d.ts +10 -0
- package/dist/tui/session-replay.js +78 -0
- package/dist/tui/session-usage.d.ts +22 -0
- package/dist/tui/session-usage.js +55 -0
- package/dist/tui/skill-transcript.d.ts +5 -0
- package/dist/tui/skill-transcript.js +31 -0
- package/dist/tui/startup.d.ts +5 -0
- package/dist/tui/startup.js +61 -0
- package/dist/tui/status-line-loader.d.ts +8 -0
- package/dist/tui/status-line-loader.js +33 -0
- package/dist/tui/status-line.d.ts +38 -0
- package/dist/tui/status-line.js +213 -0
- package/dist/tui/system-language.d.ts +8 -0
- package/dist/tui/system-language.js +41 -0
- package/dist/tui/task-labels.d.ts +2 -0
- package/dist/tui/task-labels.js +7 -0
- package/dist/tui/term-bg.d.ts +4 -0
- package/dist/tui/term-bg.js +67 -0
- package/dist/tui/terminal-screen.d.ts +12 -0
- package/dist/tui/terminal-screen.js +1 -0
- package/dist/tui/terminal-text.d.ts +7 -0
- package/dist/tui/terminal-text.js +123 -0
- package/dist/tui/theme.d.ts +25 -0
- package/dist/tui/theme.js +383 -0
- package/dist/tui/tool-style.d.ts +7 -0
- package/dist/tui/tool-style.js +119 -0
- package/dist/tui/update-prompt.d.ts +14 -0
- package/dist/tui/update-prompt.js +104 -0
- package/dist/tui/usage-footer.d.ts +9 -0
- package/dist/tui/usage-footer.js +123 -0
- package/dist/tui/vascend-login.d.ts +68 -0
- package/dist/tui/vascend-login.js +355 -0
- package/dist/tui/web-login.d.ts +28 -0
- package/dist/tui/web-login.js +115 -0
- package/dist/vascend/activity-status.d.ts +12 -0
- package/dist/vascend/activity-status.js +68 -0
- package/dist/vascend/architecture-map.d.ts +73 -0
- package/dist/vascend/architecture-map.js +424 -0
- package/dist/vascend/attention-layout.d.ts +19 -0
- package/dist/vascend/attention-layout.js +141 -0
- package/dist/vascend/budget-allocator.d.ts +31 -0
- package/dist/vascend/budget-allocator.js +79 -0
- package/dist/vascend/candidate-collector.d.ts +20 -0
- package/dist/vascend/candidate-collector.js +220 -0
- package/dist/vascend/code-events.d.ts +24 -0
- package/dist/vascend/code-events.js +304 -0
- package/dist/vascend/code-graph-memory.d.ts +38 -0
- package/dist/vascend/code-graph-memory.js +334 -0
- package/dist/vascend/code-graph-runtime.d.ts +19 -0
- package/dist/vascend/code-graph-runtime.js +190 -0
- package/dist/vascend/code-graph-types.d.ts +58 -0
- package/dist/vascend/code-graph-types.js +50 -0
- package/dist/vascend/code-parser.d.ts +4 -0
- package/dist/vascend/code-parser.js +257 -0
- package/dist/vascend/competitor-knowledge.d.ts +53 -0
- package/dist/vascend/competitor-knowledge.js +262 -0
- package/dist/vascend/completeness.d.ts +16 -0
- package/dist/vascend/completeness.js +90 -0
- package/dist/vascend/context-autotuner.d.ts +45 -0
- package/dist/vascend/context-autotuner.js +231 -0
- package/dist/vascend/context-candidate.d.ts +45 -0
- package/dist/vascend/context-candidate.js +150 -0
- package/dist/vascend/context-capsule.d.ts +51 -0
- package/dist/vascend/context-capsule.js +133 -0
- package/dist/vascend/context-fabric.d.ts +108 -0
- package/dist/vascend/context-fabric.js +480 -0
- package/dist/vascend/context-feedback-loop.d.ts +56 -0
- package/dist/vascend/context-feedback-loop.js +204 -0
- package/dist/vascend/context-learning-identity.d.ts +4 -0
- package/dist/vascend/context-learning-identity.js +8 -0
- package/dist/vascend/context-links.d.ts +14 -0
- package/dist/vascend/context-links.js +83 -0
- package/dist/vascend/context-lint.d.ts +22 -0
- package/dist/vascend/context-lint.js +91 -0
- package/dist/vascend/context-market-selection.d.ts +17 -0
- package/dist/vascend/context-market-selection.js +50 -0
- package/dist/vascend/context-metrics.d.ts +25 -0
- package/dist/vascend/context-metrics.js +57 -0
- package/dist/vascend/context-pack-render.d.ts +16 -0
- package/dist/vascend/context-pack-render.js +52 -0
- package/dist/vascend/context-pareto.d.ts +33 -0
- package/dist/vascend/context-pareto.js +165 -0
- package/dist/vascend/context-pattern-explorer.d.ts +41 -0
- package/dist/vascend/context-pattern-explorer.js +276 -0
- package/dist/vascend/context-regret.d.ts +32 -0
- package/dist/vascend/context-regret.js +93 -0
- package/dist/vascend/context-retriever.d.ts +22 -0
- package/dist/vascend/context-retriever.js +243 -0
- package/dist/vascend/context-scope-index.d.ts +5 -0
- package/dist/vascend/context-scope-index.js +96 -0
- package/dist/vascend/context-scorer.d.ts +35 -0
- package/dist/vascend/context-scorer.js +162 -0
- package/dist/vascend/context-search-index.d.ts +12 -0
- package/dist/vascend/context-search-index.js +25 -0
- package/dist/vascend/context-snapshot.d.ts +22 -0
- package/dist/vascend/context-snapshot.js +135 -0
- package/dist/vascend/context-window-compiler.d.ts +42 -0
- package/dist/vascend/context-window-compiler.js +237 -0
- package/dist/vascend/contract-memory.d.ts +61 -0
- package/dist/vascend/contract-memory.js +435 -0
- package/dist/vascend/council.d.ts +58 -0
- package/dist/vascend/council.js +337 -0
- package/dist/vascend/decision-promotion.d.ts +48 -0
- package/dist/vascend/decision-promotion.js +410 -0
- package/dist/vascend/delta-context.d.ts +12 -0
- package/dist/vascend/delta-context.js +36 -0
- package/dist/vascend/dev-context-compiler.d.ts +27 -0
- package/dist/vascend/dev-context-compiler.js +133 -0
- package/dist/vascend/dev-context-layout.d.ts +30 -0
- package/dist/vascend/dev-context-layout.js +262 -0
- package/dist/vascend/evidence-slots.d.ts +14 -0
- package/dist/vascend/evidence-slots.js +55 -0
- package/dist/vascend/expansion-levels.d.ts +15 -0
- package/dist/vascend/expansion-levels.js +178 -0
- package/dist/vascend/file-lock.d.ts +7 -0
- package/dist/vascend/file-lock.js +95 -0
- package/dist/vascend/granular-kingdom.d.ts +25 -0
- package/dist/vascend/granular-kingdom.js +259 -0
- package/dist/vascend/granular-launcher.d.ts +48 -0
- package/dist/vascend/granular-launcher.js +202 -0
- package/dist/vascend/kingdom-bus.d.ts +25 -0
- package/dist/vascend/kingdom-bus.js +54 -0
- package/dist/vascend/kingdom-channel.d.ts +22 -0
- package/dist/vascend/kingdom-channel.js +180 -0
- package/dist/vascend/kingdom-kpi.d.ts +48 -0
- package/dist/vascend/kingdom-kpi.js +172 -0
- package/dist/vascend/kingdom-live.d.ts +28 -0
- package/dist/vascend/kingdom-live.js +61 -0
- package/dist/vascend/kingdom-run.d.ts +18 -0
- package/dist/vascend/kingdom-run.js +506 -0
- package/dist/vascend/kingdom-scribe.d.ts +20 -0
- package/dist/vascend/kingdom-scribe.js +52 -0
- package/dist/vascend/kingdom.d.ts +79 -0
- package/dist/vascend/kingdom.js +870 -0
- package/dist/vascend/lexical-index.d.ts +10 -0
- package/dist/vascend/lexical-index.js +99 -0
- package/dist/vascend/lexical-search.d.ts +29 -0
- package/dist/vascend/lexical-search.js +262 -0
- package/dist/vascend/long-term-context.d.ts +51 -0
- package/dist/vascend/long-term-context.js +194 -0
- package/dist/vascend/mandate.d.ts +33 -0
- package/dist/vascend/mandate.js +107 -0
- package/dist/vascend/memory-packet.d.ts +13 -0
- package/dist/vascend/memory-packet.js +155 -0
- package/dist/vascend/memory-status.d.ts +22 -0
- package/dist/vascend/memory-status.js +73 -0
- package/dist/vascend/memory-store.d.ts +62 -0
- package/dist/vascend/memory-store.js +273 -0
- package/dist/vascend/objective-revision.d.ts +69 -0
- package/dist/vascend/objective-revision.js +319 -0
- package/dist/vascend/patch-plan-store.d.ts +33 -0
- package/dist/vascend/patch-plan-store.js +240 -0
- package/dist/vascend/patch-plan.d.ts +97 -0
- package/dist/vascend/patch-plan.js +345 -0
- package/dist/vascend/plan-progress.d.ts +11 -0
- package/dist/vascend/plan-progress.js +68 -0
- package/dist/vascend/plan-store.d.ts +64 -0
- package/dist/vascend/plan-store.js +460 -0
- package/dist/vascend/proof-chains.d.ts +19 -0
- package/dist/vascend/proof-chains.js +120 -0
- package/dist/vascend/ramification-store.d.ts +25 -0
- package/dist/vascend/ramification-store.js +94 -0
- package/dist/vascend/ramification.d.ts +193 -0
- package/dist/vascend/ramification.js +583 -0
- package/dist/vascend/recall-planner.d.ts +17 -0
- package/dist/vascend/recall-planner.js +109 -0
- package/dist/vascend/requirements.d.ts +31 -0
- package/dist/vascend/requirements.js +151 -0
- package/dist/vascend/reviewer.d.ts +9 -0
- package/dist/vascend/reviewer.js +93 -0
- package/dist/vascend/room-graph.d.ts +29 -0
- package/dist/vascend/room-graph.js +242 -0
- package/dist/vascend/room-memory.d.ts +57 -0
- package/dist/vascend/room-memory.js +631 -0
- package/dist/vascend/runtime.d.ts +84 -0
- package/dist/vascend/runtime.js +286 -0
- package/dist/vascend/self-improve.d.ts +104 -0
- package/dist/vascend/self-improve.js +396 -0
- package/dist/vascend/session-search.d.ts +52 -0
- package/dist/vascend/session-search.js +349 -0
- package/dist/vascend/supersession-graph.d.ts +14 -0
- package/dist/vascend/supersession-graph.js +70 -0
- package/dist/vascend/team-areas.d.ts +9 -0
- package/dist/vascend/team-areas.js +28 -0
- package/dist/vascend/team-handoff.d.ts +24 -0
- package/dist/vascend/team-handoff.js +37 -0
- package/dist/vascend/team-scheduler.d.ts +13 -0
- package/dist/vascend/team-scheduler.js +74 -0
- package/dist/vascend/team-session.d.ts +42 -0
- package/dist/vascend/team-session.js +142 -0
- package/dist/vascend/test-failure-memory.d.ts +76 -0
- package/dist/vascend/test-failure-memory.js +354 -0
- package/dist/vascend/token-market.d.ts +42 -0
- package/dist/vascend/token-market.js +144 -0
- package/dist/vascend/tuner-baseline-store.d.ts +52 -0
- package/dist/vascend/tuner-baseline-store.js +446 -0
- package/dist/vascend/user-profile.d.ts +44 -0
- package/dist/vascend/user-profile.js +131 -0
- package/dist/vascend/vision.d.ts +94 -0
- package/dist/vascend/vision.js +375 -0
- package/dist/vascend/work-agent.d.ts +12 -0
- package/dist/vascend/work-agent.js +83 -0
- package/dist/vascend/work-queue.d.ts +62 -0
- package/dist/vascend/work-queue.js +255 -0
- package/dist/vascend/work-runner.d.ts +64 -0
- package/dist/vascend/work-runner.js +137 -0
- package/dist/vascend/worktree.d.ts +38 -0
- package/dist/vascend/worktree.js +206 -0
- package/dist/vendor/computer-use/README.md +7 -0
- package/dist/vendor/computer-use/computer-desktop.js +211 -0
- package/dist/vendor/computer-use/computer-observe.js +315 -0
- package/dist/vendor/computer-use/computer-scripts.js +1230 -0
- package/dist/vendor/computer-use/computer-tools.js +2136 -0
- package/dist/vendor/computer-use/package.json +1 -0
- package/dist/vendor/computer-use/rac/atomic-input.js +91 -0
- package/dist/vendor/computer-use/rac/grammatica.js +101 -0
- package/dist/vendor/computer-use/rac/parser.js +185 -0
- package/dist/vendor/computer-use/rac/protocol.js +136 -0
- package/install.ps1 +30 -0
- package/install.sh +50 -0
- package/package.json +56 -0
|
@@ -0,0 +1,870 @@
|
|
|
1
|
+
import { artifactReference } from "./team-handoff.js";
|
|
2
|
+
import { ToolOutputStore } from "../core/tool-result-store.js";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { resolve, sep } from "node:path";
|
|
5
|
+
import { runTurn } from "../core/agent.js";
|
|
6
|
+
import { Session } from "../core/session.js";
|
|
7
|
+
import { createUserInbox } from "../core/user-inbox.js";
|
|
8
|
+
import { kingdomLive } from "./kingdom-live.js";
|
|
9
|
+
import { fileActor, withFileActor } from "../core/file-coordination.js";
|
|
10
|
+
import { RoomMemory } from "./room-memory.js";
|
|
11
|
+
import { VascendPlanStore } from "./plan-store.js";
|
|
12
|
+
import { formatMandate, mandateFor, mandateGoal } from "./mandate.js";
|
|
13
|
+
import { launchGranularKingdom } from "./granular-kingdom.js";
|
|
14
|
+
import { scheduleTeam, validateTeamGraph } from "./team-scheduler.js";
|
|
15
|
+
import { disjointAreas } from "./team-areas.js";
|
|
16
|
+
export { disjointAreas } from "./team-areas.js";
|
|
17
|
+
import { formatGranularReport, granularConcurrency } from "./granular-launcher.js";
|
|
18
|
+
import { worktreeMode, repoRoot, resolveBaseBranch, vassalBranchName, worktreeDir, addWorktree, commitAll, mergeBack, removeWorktree, deleteBranch, runGit, } from "./worktree.js";
|
|
19
|
+
// Estrae dai report la lista dei rami in conflitto/non-merge-ati che richiedono
|
|
20
|
+
// risoluzione manuale (rami conservati). Vuota se tutto e' filato liscio o se
|
|
21
|
+
// non si e' in modalita' worktree.
|
|
22
|
+
export function collectConflicts(reports) {
|
|
23
|
+
const out = [];
|
|
24
|
+
for (const r of reports) {
|
|
25
|
+
if (r.recovery && r.branch) {
|
|
26
|
+
out.push({
|
|
27
|
+
slug: r.slug,
|
|
28
|
+
branch: r.branch,
|
|
29
|
+
conflict: r.merge?.conflict ?? false,
|
|
30
|
+
note: r.recovery.note,
|
|
31
|
+
...(r.recovery.worktree ? { worktree: r.recovery.worktree } : {}),
|
|
32
|
+
reason: r.recovery.reason,
|
|
33
|
+
commitRequired: r.recovery.commitRequired,
|
|
34
|
+
mergeRequired: r.recovery.mergeRequired,
|
|
35
|
+
integrated: r.merge?.integrated === true,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
else if (r.merge && !r.merge.ok && r.branch) {
|
|
39
|
+
out.push({
|
|
40
|
+
slug: r.slug,
|
|
41
|
+
branch: r.branch,
|
|
42
|
+
conflict: r.merge.conflict,
|
|
43
|
+
note: r.merge.note,
|
|
44
|
+
integrated: r.merge.integrated === true,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
// Lista azionabile (notazione Danilov + comandi git) dei rami da risolvere a
|
|
51
|
+
// mano. Ritorna "" se non c'e' nulla in sospeso. `base` = ramo di integrazione
|
|
52
|
+
// su cui rifare il merge dopo la risoluzione.
|
|
53
|
+
export function formatConflictList(conflicts, base) {
|
|
54
|
+
if (!conflicts.length)
|
|
55
|
+
return "";
|
|
56
|
+
const into = base ? ` in ${base}` : "";
|
|
57
|
+
const rows = conflicts
|
|
58
|
+
.map((c) => {
|
|
59
|
+
const state = conflictState(c);
|
|
60
|
+
const wt = c.worktree ? ` · worktree=${c.worktree}` : "";
|
|
61
|
+
return `@ramo[${c.slug}]: ${c.branch} · ${state}${wt}${c.note ? ` · ${c.note}` : ""}`;
|
|
62
|
+
})
|
|
63
|
+
.join("\n");
|
|
64
|
+
const inspect = conflicts
|
|
65
|
+
.map((c) => c.worktree
|
|
66
|
+
? ` git -C ${quoteCommandArg(c.worktree)} status # ispeziona il lavoro conservato di ${c.slug}`
|
|
67
|
+
: ` git log --oneline ${base ? `${base}..` : ""}${c.branch} # ispeziona il ramo conservato di ${c.slug}`)
|
|
68
|
+
.join("\n");
|
|
69
|
+
const commits = conflicts
|
|
70
|
+
.filter((c) => c.commitRequired && c.worktree)
|
|
71
|
+
.map((c) => ` git -C ${quoteCommandArg(c.worktree)} add -A && git -C ${quoteCommandArg(c.worktree)} commit # salva prima del merge`)
|
|
72
|
+
.join("\n");
|
|
73
|
+
const merges = conflicts
|
|
74
|
+
.filter((c) => c.mergeRequired !== false && !c.integrated)
|
|
75
|
+
.map((c) => ` ${base ? `git switch ${base} && ` : ""}git merge --no-ff ${c.branch} # verifica/risolvi, poi commit se richiesto`)
|
|
76
|
+
.join("\n");
|
|
77
|
+
const cleanup = conflicts
|
|
78
|
+
.filter((c) => c.integrated)
|
|
79
|
+
.map((c) => `${c.worktree ? ` git worktree remove ${quoteCommandArg(c.worktree)}\n` : ""} git branch -d ${c.branch}`)
|
|
80
|
+
.join("\n");
|
|
81
|
+
const actions = [inspect, commits, merges, cleanup].filter(Boolean).join("\n");
|
|
82
|
+
return `[STASH_DA_RISOLVERE]
|
|
83
|
+
@stato[sospeso]: ${conflicts.length} ramo/i di collaboratore da recuperare${into} (nessun lavoro e' stato eliminato)
|
|
84
|
+
${rows}
|
|
85
|
+
@azione[risoluzione]: ispeziona, committa se indicato, poi integra SOLO dal ramo base:
|
|
86
|
+
${actions}
|
|
87
|
+
@azione[pulizia]: solo dopo aver verificato il merge: git worktree remove <path> ; git branch -d <ramo>`;
|
|
88
|
+
}
|
|
89
|
+
function quoteCommandArg(value) {
|
|
90
|
+
return `"${value.replace(/\\/g, "/").replace(/"/g, '\\"')}"`;
|
|
91
|
+
}
|
|
92
|
+
function conflictState(entry) {
|
|
93
|
+
if (entry.integrated)
|
|
94
|
+
return "merge completato, pulizia sospesa";
|
|
95
|
+
if (entry.conflict)
|
|
96
|
+
return "CONFLITTO di merge";
|
|
97
|
+
if (entry.reason === "vassal-failed")
|
|
98
|
+
return "collaboratore fallito, lavoro conservato";
|
|
99
|
+
if (entry.reason === "setup-failed")
|
|
100
|
+
return "setup worktree fallito";
|
|
101
|
+
if (entry.reason === "commit-failed")
|
|
102
|
+
return "commit fallito, lavoro conservato";
|
|
103
|
+
return "merge fallito";
|
|
104
|
+
}
|
|
105
|
+
export function warmConcurrency(env, fallback = 8) {
|
|
106
|
+
const n = Number(env["TALOS_KINGDOM_CONCURRENCY"]);
|
|
107
|
+
return Number.isInteger(n) && n > 0 ? n : fallback;
|
|
108
|
+
}
|
|
109
|
+
// Euristica "obiettivo grande": evita di scomporre i prompt piccoli (la
|
|
110
|
+
// scomposizione costa una chiamata al modello). Conservativa.
|
|
111
|
+
export function looksBigGoal(text) {
|
|
112
|
+
const t = text.trim();
|
|
113
|
+
if (t.length >= 240)
|
|
114
|
+
return true;
|
|
115
|
+
if (t.split("\n").filter((l) => l.trim()).length >= 4)
|
|
116
|
+
return true;
|
|
117
|
+
const signals = (t.match(/\b(e poi|inoltre|vari|varie|multipl|in parallelo|workstream|diverse|diversi|piu'|più|oltre a)\b/gi) ?? []).length;
|
|
118
|
+
return signals >= 2;
|
|
119
|
+
}
|
|
120
|
+
const DECOMPOSE_SYSTEM = `# Coordinatore del team
|
|
121
|
+
|
|
122
|
+
INDICE
|
|
123
|
+
1 = coordinatore
|
|
124
|
+
2 = obiettivo
|
|
125
|
+
3 = incarico
|
|
126
|
+
4 = indipendenza
|
|
127
|
+
5 = confine
|
|
128
|
+
|
|
129
|
+
DEFINIZIONI
|
|
130
|
+
@coordinatore[ruolo]: scompone un obiettivo grande in incarichi
|
|
131
|
+
@obiettivo[input]: macro-goal da spezzare
|
|
132
|
+
@incarico[unita]: sotto-obiettivo autonomo, che un collaboratore puo' portare a termine da solo
|
|
133
|
+
@indipendenza[regola]: gli incarichi non dipendono dall'output l'uno dell'altro nello stesso giro
|
|
134
|
+
@confine[criterio]: taglia per area/modulo/file, NON per fase sequenziale
|
|
135
|
+
|
|
136
|
+
RELAZIONI
|
|
137
|
+
@R1: @obiettivo[input] -> @incarico[unita] [ scomponi in parti ]
|
|
138
|
+
@R2: @incarico[unita] -> @indipendenza[regola] [ partono tutti insieme ]
|
|
139
|
+
@R3: @incarico[unita] -> @confine[criterio] [ confini netti ]
|
|
140
|
+
|
|
141
|
+
OUTPUT: SOLO un array JSON di {slug, goal, after}; slug kebab-case breve; goal autonomo e completo;
|
|
142
|
+
"after" = array degli slug degli incarichi PREREQUISITO (dipendenze forti: cio' che deve esistere prima),
|
|
143
|
+
[] se indipendente — e indipendente e' quasi sempre la risposta giusta: un "after" di troppo mette in
|
|
144
|
+
fila lavoro che poteva andare in parallelo. Niente prosa, niente markdown.`;
|
|
145
|
+
// L'Imperatore scompone un obiettivo in castelli (slug + goal) con UNA chiamata
|
|
146
|
+
// al modello. Ritorna [] se non risolvibile; fallback a un solo castello se il
|
|
147
|
+
// parsing fallisce.
|
|
148
|
+
export async function decomposeKingdom(opts) {
|
|
149
|
+
const { harness, goal, signal } = opts;
|
|
150
|
+
const max = Math.max(2, opts.max ?? 6);
|
|
151
|
+
const resolved = harness.providers.resolve(harness.config.model);
|
|
152
|
+
if (!resolved)
|
|
153
|
+
return [];
|
|
154
|
+
const user = `Obiettivo:\n${goal}\n\nScomponilo in al massimo ${max} incarichi INDIPENDENTI.\n` +
|
|
155
|
+
`Rispondi SOLO con un array JSON di oggetti {"slug","goal"}: slug breve in kebab-case (max 24 char), ` +
|
|
156
|
+
`goal autonomo e completo (una frase eseguibile). Niente prosa, niente markdown, solo l'array JSON.`;
|
|
157
|
+
const res = await resolved.provider.complete({
|
|
158
|
+
system: DECOMPOSE_SYSTEM,
|
|
159
|
+
messages: [{ role: "user", content: [{ type: "text", text: user }] }],
|
|
160
|
+
tools: [],
|
|
161
|
+
model: resolved.modelId,
|
|
162
|
+
maxTokens: harness.config.maxTokens,
|
|
163
|
+
signal,
|
|
164
|
+
sessionId: `decompose-${harness.session.id}`,
|
|
165
|
+
});
|
|
166
|
+
const parsed = parseCastlesJson(res.text);
|
|
167
|
+
if (parsed.length)
|
|
168
|
+
return parsed.slice(0, max);
|
|
169
|
+
return [{ slug: "c1", goal }];
|
|
170
|
+
}
|
|
171
|
+
function parseCastlesJson(text) {
|
|
172
|
+
const m = /\[[\s\S]*\]/.exec(text);
|
|
173
|
+
if (!m)
|
|
174
|
+
return [];
|
|
175
|
+
let raw;
|
|
176
|
+
try {
|
|
177
|
+
raw = JSON.parse(m[0]);
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
return [];
|
|
181
|
+
}
|
|
182
|
+
if (!Array.isArray(raw))
|
|
183
|
+
return [];
|
|
184
|
+
const out = [];
|
|
185
|
+
const seen = new Set();
|
|
186
|
+
raw.forEach((item, i) => {
|
|
187
|
+
if (!item || typeof item !== "object")
|
|
188
|
+
return;
|
|
189
|
+
const o = item;
|
|
190
|
+
const goal = typeof o["goal"] === "string" ? o["goal"].trim() : "";
|
|
191
|
+
if (!goal)
|
|
192
|
+
return;
|
|
193
|
+
let slug = (typeof o["slug"] === "string" ? o["slug"] : `c${i + 1}`)
|
|
194
|
+
.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 24) || `c${i + 1}`;
|
|
195
|
+
while (seen.has(slug))
|
|
196
|
+
slug = `${slug}-${i + 1}`;
|
|
197
|
+
seen.add(slug);
|
|
198
|
+
const after = Array.isArray(o["after"])
|
|
199
|
+
? o["after"].map(String).map((s) => s.trim()).filter(Boolean)
|
|
200
|
+
: [];
|
|
201
|
+
const list = (value) => Array.isArray(value)
|
|
202
|
+
? value.map(String).map((entry) => entry.trim()).filter(Boolean).slice(0, 64)
|
|
203
|
+
: [];
|
|
204
|
+
const toolsRaw = o["tools"] && typeof o["tools"] === "object" && !Array.isArray(o["tools"])
|
|
205
|
+
? o["tools"]
|
|
206
|
+
: null;
|
|
207
|
+
const allow = list(toolsRaw?.["allow"]);
|
|
208
|
+
const deny = list(toolsRaw?.["deny"]);
|
|
209
|
+
const effort = ["low", "medium", "high", "max"].includes(String(o["effort"] ?? "").toLowerCase())
|
|
210
|
+
? String(o["effort"]).toLowerCase()
|
|
211
|
+
: "";
|
|
212
|
+
out.push({
|
|
213
|
+
slug,
|
|
214
|
+
goal,
|
|
215
|
+
...(after.length ? { after } : {}),
|
|
216
|
+
...(typeof o["parent"] === "string" && o["parent"].trim() ? { parent: o["parent"].trim().slice(0, 80) } : {}),
|
|
217
|
+
...(typeof o["role"] === "string" && o["role"].trim() ? { role: o["role"].trim().slice(0, 80) } : {}),
|
|
218
|
+
...(typeof o["model"] === "string" && o["model"].trim() ? { model: o["model"].trim().slice(0, 180) } : {}),
|
|
219
|
+
...(effort ? { effort } : {}),
|
|
220
|
+
...(typeof o["instructions"] === "string" && o["instructions"].trim()
|
|
221
|
+
? { instructions: o["instructions"].trim().slice(0, 12_000) }
|
|
222
|
+
: {}),
|
|
223
|
+
...(allow.length || deny.length
|
|
224
|
+
? { tools: { ...(allow.length ? { allow } : {}), ...(deny.length ? { deny } : {}) } }
|
|
225
|
+
: {}),
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
// Pulisce le dipendenze: tieni solo gli slug esistenti e niente auto-dipendenza.
|
|
229
|
+
const slugs = new Set(out.map((c) => c.slug));
|
|
230
|
+
return out.map((c) => {
|
|
231
|
+
const dep = (c.after ?? []).filter((a) => a !== c.slug && slugs.has(a));
|
|
232
|
+
if (dep.length)
|
|
233
|
+
return { ...c, after: dep };
|
|
234
|
+
const { after: _after, ...rest } = c;
|
|
235
|
+
return rest;
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
// Unico punto che puo' integrare e pulire un worktree. La sequenza e'
|
|
239
|
+
// deliberatamente monotona: commit verificato -> merge verificato -> remove
|
|
240
|
+
// non forzato -> branch delete non forzato. A ogni errore si ferma e pubblica
|
|
241
|
+
// un recovery report; non esiste alcun percorso che faccia cleanup anticipato.
|
|
242
|
+
export async function finalizeVassalWorktree(opts) {
|
|
243
|
+
const { root, base, branch, dir, report, signal } = opts;
|
|
244
|
+
const committed = await commitAll(dir, `team(${report.slug}): lavoro del collaboratore`, signal);
|
|
245
|
+
if (!committed.ok) {
|
|
246
|
+
const note = `${committed.note}; merge non eseguito; ramo ${branch} e worktree ${dir} conservati`;
|
|
247
|
+
return recoveryReport(report, branch, dir, "commit-failed", note, true, true, {
|
|
248
|
+
ok: false,
|
|
249
|
+
conflict: false,
|
|
250
|
+
integrated: false,
|
|
251
|
+
note,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
// Un vassallo fallito puo' aver prodotto lavoro parziale utile. Lo mettiamo
|
|
255
|
+
// al sicuro nel suo ramo, ma non lo integriamo automaticamente nel base.
|
|
256
|
+
if (!report.ok) {
|
|
257
|
+
const saved = committed.committed ? "lavoro parziale committato" : "ramo gia' pulito";
|
|
258
|
+
const note = `collaboratore fallito; ${saved}; verifica manuale richiesta prima del merge; ramo ${branch} e worktree ${dir} conservati`;
|
|
259
|
+
return recoveryReport(report, branch, dir, "vassal-failed", note, false, true, {
|
|
260
|
+
ok: false,
|
|
261
|
+
conflict: false,
|
|
262
|
+
integrated: false,
|
|
263
|
+
note,
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
const merged = await mergeBack(root, base, branch, `merge team(${report.slug}) in ${base}`, signal);
|
|
267
|
+
if (!merged.ok) {
|
|
268
|
+
const note = `${merged.note}; ramo ${branch} e worktree ${dir} conservati`;
|
|
269
|
+
return recoveryReport(report, branch, dir, "merge-failed", note, false, true, { ...merged, note });
|
|
270
|
+
}
|
|
271
|
+
const removed = await removeWorktree(root, dir, signal);
|
|
272
|
+
if (removed.code !== 0) {
|
|
273
|
+
const detail = gitResultDetail(removed);
|
|
274
|
+
const note = `merge verificato in ${base}, ma rimozione worktree fallita: ${detail}; ramo ${branch} e worktree ${dir} conservati`;
|
|
275
|
+
return recoveryReport(report, branch, dir, "cleanup-failed", note, false, false, { ...merged, note });
|
|
276
|
+
}
|
|
277
|
+
const deleted = await deleteBranch(root, branch, signal);
|
|
278
|
+
if (deleted.code !== 0) {
|
|
279
|
+
const detail = gitResultDetail(deleted);
|
|
280
|
+
const note = `merge verificato e worktree rimosso, ma eliminazione ramo fallita: ${detail}; ramo ${branch} conservato`;
|
|
281
|
+
return recoveryReport(report, branch, undefined, "cleanup-failed", note, false, false, { ...merged, note });
|
|
282
|
+
}
|
|
283
|
+
return { ...report, branch, merge: merged };
|
|
284
|
+
}
|
|
285
|
+
function recoveryReport(report, branch, worktree, reason, note, commitRequired, mergeRequired, merge) {
|
|
286
|
+
const error = report.error ? `${report.error}; ${note}` : note;
|
|
287
|
+
const recovery = {
|
|
288
|
+
reason,
|
|
289
|
+
...(worktree ? { worktree } : {}),
|
|
290
|
+
commitRequired,
|
|
291
|
+
mergeRequired,
|
|
292
|
+
note,
|
|
293
|
+
};
|
|
294
|
+
return {
|
|
295
|
+
...report,
|
|
296
|
+
ok: false,
|
|
297
|
+
error,
|
|
298
|
+
branch,
|
|
299
|
+
...(worktree ? { worktree } : {}),
|
|
300
|
+
merge,
|
|
301
|
+
recovery,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
function gitResultDetail(result) {
|
|
305
|
+
return (result.stderr || result.stdout || `uscita ${result.code}`).trim().slice(0, 360);
|
|
306
|
+
}
|
|
307
|
+
export async function runKingdomWarm(opts) {
|
|
308
|
+
const { harness, kingdomId, castles, signal, onNotice } = opts;
|
|
309
|
+
const env = process.env;
|
|
310
|
+
validateTeamGraph(castles);
|
|
311
|
+
// Setup ISOLAMENTO via worktree (se richiesto e siamo in un repo git). I
|
|
312
|
+
// worktree si creano in SEQUENZA (toccano lo stato condiviso del repo) prima
|
|
313
|
+
// di lanciare i vassalli in parallelo.
|
|
314
|
+
const wantWt = opts.worktree ?? worktreeMode(env);
|
|
315
|
+
const root = wantWt ? await repoRoot(harness.config.cwd) : null;
|
|
316
|
+
const base = root ? await resolveBaseBranch(root, env, opts.baseBranch) : null;
|
|
317
|
+
const useWt = Boolean(root && base);
|
|
318
|
+
const wt = new Map();
|
|
319
|
+
const setupFailures = new Map();
|
|
320
|
+
if (useWt) {
|
|
321
|
+
// I worktree sono l'unica cosa che il regno scrive PRIMA di qualsiasi
|
|
322
|
+
// lavoro: creano rami e cartelle nel repo dell'utente. Vanno chiesti come
|
|
323
|
+
// ogni altra azione che tocca il disco, e vanno chiesti UNA volta per tutto
|
|
324
|
+
// il regno, non una per castello.
|
|
325
|
+
const dirs = worktreeDir(kingdomId, castles[0]?.slug ?? "castello");
|
|
326
|
+
const approved = await opts.confirm("git worktree", `${castles.length} worktree isolati da "${base}" (un ramo ${vassalBranchName(kingdomId, "<gruppo>")} per gruppo), `
|
|
327
|
+
+ `sotto ${dirs.slice(0, dirs.lastIndexOf(sep) + 1) || dirs}; merge seriali nel ramo base al completamento`);
|
|
328
|
+
if (!approved) {
|
|
329
|
+
// Rifiutato: non si ripiega sulla working dir condivisa, che sarebbe piu'
|
|
330
|
+
// invasiva (tutti i vassalli a scrivere nella stessa copia), non meno.
|
|
331
|
+
return castles.map((c) => ({
|
|
332
|
+
slug: c.slug,
|
|
333
|
+
ok: false,
|
|
334
|
+
summary: "",
|
|
335
|
+
rooms: 0,
|
|
336
|
+
error: "worktree isolati non autorizzati: piano non avviato. Per lavorare senza isolamento, nella stessa working dir, riavvia con TALOS_KINGDOM_WORKTREE=0",
|
|
337
|
+
}));
|
|
338
|
+
}
|
|
339
|
+
onNotice?.(`worktree isolati · ramo base "${base}" · merge a fine corsa`);
|
|
340
|
+
for (const c of castles) {
|
|
341
|
+
if (signal.aborted)
|
|
342
|
+
break;
|
|
343
|
+
const branch = vassalBranchName(kingdomId, c.slug);
|
|
344
|
+
const dir = worktreeDir(kingdomId, c.slug);
|
|
345
|
+
const r = await addWorktree(root, dir, branch, base, signal);
|
|
346
|
+
if (r.code === 0)
|
|
347
|
+
wt.set(c.slug, { dir, branch });
|
|
348
|
+
else {
|
|
349
|
+
const detail = gitResultDetail(r);
|
|
350
|
+
const note = `worktree non creato: ${detail}; nessun collaboratore avviato in working dir condivisa; eventuale ramo/worktree preesistente lasciato intatto`;
|
|
351
|
+
setupFailures.set(c.slug, { dir, branch, note });
|
|
352
|
+
onNotice?.(`[${c.slug}] ${note}`);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
else if (wantWt) {
|
|
357
|
+
onNotice?.(root
|
|
358
|
+
? "nessun ramo base (HEAD staccato?): niente worktree, modalita' condivisa + commit unico finale"
|
|
359
|
+
: "non e' un repo git: niente worktree, modalita' condivisa + commit unico finale");
|
|
360
|
+
}
|
|
361
|
+
const requestedLimit = Math.max(1, opts.concurrency ?? warmConcurrency(env));
|
|
362
|
+
/* Senza worktree i collaboratori scrivono nella STESSA cartella, e due
|
|
363
|
+
write sullo stesso file si sovrascrivono. La coda seriale era la difesa,
|
|
364
|
+
ma pagata da tutti: anche tre lavori che non si toccano nemmeno partivano
|
|
365
|
+
uno alla volta, e una squadra diventava una fila.
|
|
366
|
+
La difesa ora e' mirata: chi dichiara la propria AREA e non si sovrappone
|
|
367
|
+
a nessun altro parte subito; si resta in fila solo se le aree mancano o
|
|
368
|
+
si incrociano, cioe' quando il conflitto e' davvero possibile. */
|
|
369
|
+
const aree = disjointAreas(castles, harness.config.cwd);
|
|
370
|
+
const limit = requestedLimit;
|
|
371
|
+
if (!useWt && castles.length > 1 && !aree.disjoint) {
|
|
372
|
+
onNotice?.(`Coordinamento nella stessa cartella: ${aree.detail}. `
|
|
373
|
+
+ "Gli incarichi con aree sovrapposte o mancanti vengono serializzati; dichiara l'area "
|
|
374
|
+
+ "per eseguire contemporaneamente i lavori indipendenti.");
|
|
375
|
+
}
|
|
376
|
+
const peers = castles.map((c) => c.slug);
|
|
377
|
+
const handoffs = new Map();
|
|
378
|
+
const executeMember = async (castle, i) => {
|
|
379
|
+
const setupFailure = setupFailures.get(castle.slug);
|
|
380
|
+
if (setupFailure) {
|
|
381
|
+
const hasWorktree = existsSync(setupFailure.dir);
|
|
382
|
+
return {
|
|
383
|
+
slug: castle.slug,
|
|
384
|
+
ok: false,
|
|
385
|
+
summary: "",
|
|
386
|
+
rooms: 0,
|
|
387
|
+
error: setupFailure.note,
|
|
388
|
+
branch: setupFailure.branch,
|
|
389
|
+
...(hasWorktree ? { worktree: setupFailure.dir } : {}),
|
|
390
|
+
merge: { ok: false, conflict: false, integrated: false, note: setupFailure.note },
|
|
391
|
+
recovery: {
|
|
392
|
+
reason: "setup-failed",
|
|
393
|
+
...(hasWorktree ? { worktree: setupFailure.dir } : {}),
|
|
394
|
+
commitRequired: false,
|
|
395
|
+
mergeRequired: false,
|
|
396
|
+
note: setupFailure.note,
|
|
397
|
+
},
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
const w = wt.get(castle.slug);
|
|
401
|
+
const workerPool = Array.isArray(harness.config.workerModelPool)
|
|
402
|
+
? harness.config.workerModelPool : undefined;
|
|
403
|
+
const requested = castle.model?.trim() || "";
|
|
404
|
+
const selected = requested || (workerPool && workerPool.length
|
|
405
|
+
? workerPool[i % workerPool.length]
|
|
406
|
+
: harness.config.model);
|
|
407
|
+
if (workerPool && (!workerPool.length || !workerPool.includes(selected))) {
|
|
408
|
+
return {
|
|
409
|
+
slug: castle.slug,
|
|
410
|
+
ok: false,
|
|
411
|
+
summary: "",
|
|
412
|
+
rooms: 0,
|
|
413
|
+
model: selected,
|
|
414
|
+
...(castle.role ? { role: castle.role } : {}),
|
|
415
|
+
parent: castle.parent ?? "orchestratore",
|
|
416
|
+
error: workerPool.length
|
|
417
|
+
? `modello collaboratore non autorizzato: ${selected}`
|
|
418
|
+
: "nessun modello collaboratore autorizzato dall'utente",
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
const resolved = harness.providers.resolve(selected);
|
|
422
|
+
if (!resolved) {
|
|
423
|
+
return {
|
|
424
|
+
slug: castle.slug,
|
|
425
|
+
ok: false,
|
|
426
|
+
summary: "",
|
|
427
|
+
rooms: 0,
|
|
428
|
+
model: selected,
|
|
429
|
+
...(castle.role ? { role: castle.role } : {}),
|
|
430
|
+
parent: castle.parent ?? "orchestratore",
|
|
431
|
+
error: `modello non configurato: ${selected}`,
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
return runVassal(opts, resolved.provider, resolved.modelId, selected, castle, peers, {
|
|
435
|
+
cwd: w?.dir,
|
|
436
|
+
isolated: Boolean(w),
|
|
437
|
+
base: base ?? undefined,
|
|
438
|
+
}, (castle.after ?? []).map((slug) => handoffs.get(slug)).filter(Boolean));
|
|
439
|
+
};
|
|
440
|
+
// Integration mutates the shared repository. Serialize it, while allowing
|
|
441
|
+
// independent agents to continue working in their own worktrees.
|
|
442
|
+
let integration = Promise.resolve();
|
|
443
|
+
const integrate = (action) => {
|
|
444
|
+
const next = integration.then(action);
|
|
445
|
+
integration = next.catch(() => undefined);
|
|
446
|
+
return next;
|
|
447
|
+
};
|
|
448
|
+
const reports = await scheduleTeam({
|
|
449
|
+
members: castles, concurrency: limit, signal,
|
|
450
|
+
compatible: (left, right) => useWt || disjointAreas([left, right], harness.config.cwd).disjoint,
|
|
451
|
+
failure: (castle, error) => {
|
|
452
|
+
const w = wt.get(castle.slug);
|
|
453
|
+
return { slug: castle.slug, ok: false, summary: "", rooms: 0, error,
|
|
454
|
+
...(w ? { branch: w.branch, worktree: w.dir, recovery: {
|
|
455
|
+
reason: "vassal-failed", worktree: w.dir, commitRequired: false, mergeRequired: false,
|
|
456
|
+
note: `${error}; worktree non eseguito conservato in ${w.dir}`,
|
|
457
|
+
} } : {}),
|
|
458
|
+
};
|
|
459
|
+
},
|
|
460
|
+
run: async (castle, index) => {
|
|
461
|
+
const w = wt.get(castle.slug);
|
|
462
|
+
if (w && castle.after?.length) {
|
|
463
|
+
const synced = await integrate(() => runGit(w.dir, ["merge", "--ff-only", base], signal));
|
|
464
|
+
if (synced.code !== 0)
|
|
465
|
+
throw new Error(`impossibile acquisire i prerequisiti in ${w.dir}: ${gitResultDetail(synced)}`);
|
|
466
|
+
}
|
|
467
|
+
opts.onMemberState?.(castle.slug, "running");
|
|
468
|
+
const report = await executeMember(castle, index);
|
|
469
|
+
if (!w || signal.aborted)
|
|
470
|
+
return report;
|
|
471
|
+
const finalized = await integrate(() => signal.aborted ? Promise.resolve(report) : finalizeVassalWorktree({
|
|
472
|
+
root: root, base: base, branch: w.branch, dir: w.dir, report, signal,
|
|
473
|
+
}));
|
|
474
|
+
onNotice?.(finalized.merge?.ok ? `[${castle.slug}] merge verificato in ${base}; cleanup completato`
|
|
475
|
+
: `[${castle.slug}] integrazione sospesa: ${finalized.recovery?.note ?? finalized.error ?? "errore"}`);
|
|
476
|
+
return finalized;
|
|
477
|
+
},
|
|
478
|
+
settled: (castle, report) => {
|
|
479
|
+
handoffs.set(castle.slug, report);
|
|
480
|
+
opts.onMemberState?.(castle.slug, report.ok ? "completed" : "failed", report);
|
|
481
|
+
},
|
|
482
|
+
});
|
|
483
|
+
if (signal.aborted) {
|
|
484
|
+
// Non eseguire commit/merge seriali dopo lo stop: erano la parte che
|
|
485
|
+
// faceva sembrare il comando bloccato. I worktree con lavoro parziale
|
|
486
|
+
// restano esplicitamente recuperabili, senza fondere modifiche incomplete.
|
|
487
|
+
onNotice?.("swarm arrestato; nessun merge ulteriore del lavoro parziale");
|
|
488
|
+
return castles.map((castle, index) => {
|
|
489
|
+
const report = reports[index];
|
|
490
|
+
const w = wt.get(castle.slug);
|
|
491
|
+
const note = w
|
|
492
|
+
? `arrestato prima del completamento; worktree conservato in ${w.dir}`
|
|
493
|
+
: "arrestato prima dell'avvio";
|
|
494
|
+
if (report) {
|
|
495
|
+
if (report.merge?.ok)
|
|
496
|
+
return report;
|
|
497
|
+
return w ? {
|
|
498
|
+
...report,
|
|
499
|
+
ok: false,
|
|
500
|
+
error: report.error || note,
|
|
501
|
+
branch: w.branch,
|
|
502
|
+
worktree: w.dir,
|
|
503
|
+
recovery: {
|
|
504
|
+
reason: "vassal-failed",
|
|
505
|
+
worktree: w.dir,
|
|
506
|
+
commitRequired: true,
|
|
507
|
+
mergeRequired: true,
|
|
508
|
+
note,
|
|
509
|
+
},
|
|
510
|
+
} : report;
|
|
511
|
+
}
|
|
512
|
+
return {
|
|
513
|
+
slug: castle.slug,
|
|
514
|
+
ok: false,
|
|
515
|
+
summary: "",
|
|
516
|
+
rooms: 0,
|
|
517
|
+
model: castle.model?.trim() || harness.config.model,
|
|
518
|
+
role: castle.role?.trim() || "collaboratore",
|
|
519
|
+
parent: castle.parent?.trim() || "orchestratore",
|
|
520
|
+
...(castle.castle ? { workstreamId: castle.castle } : {}),
|
|
521
|
+
...(castle.tasks?.length ? { taskRefs: [...castle.tasks] } : {}),
|
|
522
|
+
error: note,
|
|
523
|
+
...(w ? {
|
|
524
|
+
branch: w.branch,
|
|
525
|
+
worktree: w.dir,
|
|
526
|
+
recovery: {
|
|
527
|
+
reason: "vassal-failed",
|
|
528
|
+
worktree: w.dir,
|
|
529
|
+
commitRequired: true,
|
|
530
|
+
mergeRequired: true,
|
|
531
|
+
note,
|
|
532
|
+
},
|
|
533
|
+
} : {}),
|
|
534
|
+
};
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
return reports;
|
|
538
|
+
}
|
|
539
|
+
// Preambolo di coordinamento del vassallo: chi e', con chi collabora, le sue
|
|
540
|
+
// dipendenze, e come cooperare attivamente (annuncia/aspetta) via i kingdom tool.
|
|
541
|
+
function vassalSteer(self, peers, after, identity, git, mandateBlock) {
|
|
542
|
+
const others = peers.filter((p) => p !== self);
|
|
543
|
+
// Regola git diversa per modalita': isolato (worktree dedicato → committa sul
|
|
544
|
+
// tuo ramo) vs condiviso (working dir comune → niente git che muta).
|
|
545
|
+
const gitDef = git.isolated
|
|
546
|
+
? `@git[isolato]: lavori in una working dir TUA (worktree) su un ramo TUO; usa PATH RELATIVI; committa il tuo lavoro qui (git add/commit liberi). Chi ti ha ingaggiato fara' il merge del tuo ramo in "${git.base ?? "base"}". NON cambiare ramo/checkout/reset, NON toccare altri worktree.`
|
|
547
|
+
: `@git[condiviso]: NON eseguire git che modifica (add/commit/push/pull/reset/checkout/stash/clean): condividi la STESSA working dir con gli altri, vi sovrascrivereste; modifica SOLO i file, il commit avviene UNA volta sola alla fine fuori dallo swarm (git status/diff sono ok)`;
|
|
548
|
+
const gitRel = git.isolated
|
|
549
|
+
? `@R4: @ruolo[collaboratore] -> @git[isolato] [ committa sul tuo ramo, path relativi ]`
|
|
550
|
+
: `@R4: @ruolo[collaboratore] -> @git[condiviso] [ niente git che muta, solo edit dei file ]`;
|
|
551
|
+
const gitOut = git.isolated
|
|
552
|
+
? `committa il tuo lavoro sul TUO ramo (il merge lo fa chi ti ha ingaggiato).`
|
|
553
|
+
: `NIENTE git che modifica.`;
|
|
554
|
+
return `[COLLABORATORE ${self}]
|
|
555
|
+
INDICE
|
|
556
|
+
1 = ruolo
|
|
557
|
+
2 = dipendenze
|
|
558
|
+
3 = cooperazione
|
|
559
|
+
4 = confine
|
|
560
|
+
|
|
561
|
+
DEFINIZIONI
|
|
562
|
+
@ruolo[collaboratore]: id=${self}, ruolo=${identity.role}, parent=${identity.parent}, peer=[${others.join(", ") || "nessuno"}]
|
|
563
|
+
@dipendenze[after]: ${after.length ? after.join(", ") : "nessuna (parti subito)"}
|
|
564
|
+
@cooperazione[annuncio]: all'avvio usa team_say(to="${identity.parent}") per confermare task e piano breve; durante il lavoro annuncia milestone; alla fine invia esito e file toccati
|
|
565
|
+
@cooperazione[ascolto]: team_inbox REGOLARMENTE — dopo ogni passaggio, non solo se dipendi da qualcuno: chi ti scrive puo' averti risparmiato un lavoro sbagliato, o aspettare una tua risposta
|
|
566
|
+
@cooperazione[attesa]: team_wait(from/contains) solo se non hai altro di utile da fare; se puoi andare avanti su un altro pezzo, vai avanti
|
|
567
|
+
@cooperazione[info]: tieni informato chi dipende da te, e rispondi a chi ti chiede qualcosa: un messaggio senza risposta blocca chi l'ha mandato
|
|
568
|
+
@cooperazione[scoperte]: se scopri qualcosa che cambia il lavoro di un altro (un file che non e' dove sembrava, un'assunzione che non regge) diglielo SUBITO con team_say, prima che ci sbatta anche lui
|
|
569
|
+
@confine[regola]: resta nel tuo incarico, non duplicare il lavoro altrui
|
|
570
|
+
${gitDef}
|
|
571
|
+
|
|
572
|
+
RELAZIONI
|
|
573
|
+
@R1: @cooperazione[ascolto] -> @cooperazione[scoperte] [ si lavora insieme, non in parallelo silenzioso ]
|
|
574
|
+
@R2: @ruolo[collaboratore] -> @cooperazione[annuncio] [ sblocca gli altri annunciando ]
|
|
575
|
+
@R3: @ruolo[collaboratore] -> @confine[regola] [ niente sovrapposizioni ]
|
|
576
|
+
${gitRel}
|
|
577
|
+
|
|
578
|
+
OUTPUT: esegui il tuo incarico cooperando con gli altri (annuncia/ascolta/aspetta), resta nel confine, ${gitOut}
|
|
579
|
+
|
|
580
|
+
${mandateBlock ? `${mandateBlock}\n\n` : ""}OBIETTIVO_ATTIVITA
|
|
581
|
+
`;
|
|
582
|
+
}
|
|
583
|
+
const MAX_UNITS = 16;
|
|
584
|
+
// Mandato del collaboratore: il castello del PIANO che gli e' stato affidato.
|
|
585
|
+
// Assente quando l'assegnazione e' solo una frase (nessun `castle`).
|
|
586
|
+
function resolveMandate(sessionDir, planStoreId, castle) {
|
|
587
|
+
if (!castle.castle)
|
|
588
|
+
return null;
|
|
589
|
+
const store = VascendPlanStore.open(sessionDir, planStoreId, { strict: true });
|
|
590
|
+
const plan = store.castle(castle.castle);
|
|
591
|
+
if (!plan)
|
|
592
|
+
throw new Error(`gruppo assegnato non trovato: ${castle.castle}`);
|
|
593
|
+
for (const ref of castle.tasks ?? []) {
|
|
594
|
+
if (!plan.tasks.some((task) => task.id.toLowerCase() === ref.toLowerCase() || String(task.bit) === ref)) {
|
|
595
|
+
throw new Error(`attivita assegnata non trovata: ${castle.castle}/${ref}`);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
const mandate = mandateFor(store, castle.castle, castle.tasks);
|
|
599
|
+
if (!mandate)
|
|
600
|
+
throw new Error(`nessun task aperto nel gruppo assegnato: ${castle.castle}`);
|
|
601
|
+
return mandate;
|
|
602
|
+
}
|
|
603
|
+
function unitGoal(goal, files, skills) {
|
|
604
|
+
const hints = [
|
|
605
|
+
files?.length ? `file: ${files.join(", ")}` : "",
|
|
606
|
+
skills?.length ? `skill: ${skills.join(", ")}` : "",
|
|
607
|
+
].filter(Boolean).join(" · ");
|
|
608
|
+
return hints ? `${goal}\n(${hints})` : goal;
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Converte le richieste del vassallo in unita' del team. Quando lo slug e' un
|
|
612
|
+
* ref del suo mandato (T01...) l'unita' EREDITA la stanza: titolo, peso, file e
|
|
613
|
+
* skill che l'orchestratore aveva gia' allegato al piano.
|
|
614
|
+
*/
|
|
615
|
+
function toUnits(specs, mandate) {
|
|
616
|
+
const rooms = new Map((mandate?.rooms ?? []).map((room) => [room.ref.toLowerCase(), room]));
|
|
617
|
+
const built = [];
|
|
618
|
+
const seen = new Set();
|
|
619
|
+
for (const spec of specs.slice(0, MAX_UNITS)) {
|
|
620
|
+
const raw = String(spec.slug ?? "").trim();
|
|
621
|
+
if (!raw)
|
|
622
|
+
continue;
|
|
623
|
+
const room = rooms.get(raw.toLowerCase());
|
|
624
|
+
const id = room ? room.ref : raw;
|
|
625
|
+
if (seen.has(id.toLowerCase()))
|
|
626
|
+
continue;
|
|
627
|
+
const goal = String(spec.goal ?? "").trim() || room?.title || "";
|
|
628
|
+
if (!goal)
|
|
629
|
+
continue;
|
|
630
|
+
seen.add(id.toLowerCase());
|
|
631
|
+
built.push({
|
|
632
|
+
id,
|
|
633
|
+
goal: room ? unitGoal(goal, room.files, room.skills) : goal,
|
|
634
|
+
assignment: { ...spec, ...(room && !spec.area?.length && room.files?.length ? { area: room.files } : {}) },
|
|
635
|
+
...(spec.after?.length ? { deps: [...spec.after] } : {}),
|
|
636
|
+
...(room?.weight ? { weight: room.weight } : {}),
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
// Preserve unknown dependencies so validation reports them instead of
|
|
640
|
+
// silently starting a task whose prerequisite was never assigned.
|
|
641
|
+
const ids = new Map(built.map((unit) => [unit.id.toLowerCase(), unit.id]));
|
|
642
|
+
return built.map((unit) => {
|
|
643
|
+
const deps = (unit.deps ?? [])
|
|
644
|
+
.map((dep) => ids.get(String(dep).trim().toLowerCase()) ?? dep);
|
|
645
|
+
const { deps: _drop, ...rest } = unit;
|
|
646
|
+
return deps.length ? { ...rest, deps: [...new Set(deps)] } : rest;
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
/**
|
|
650
|
+
* Delega dal collaboratore: forma un team sulle proprie stanze. Il granular
|
|
651
|
+
* launcher mantiene il grafo delle dipendenze e puo' propagare la facolta' di
|
|
652
|
+
* spawn ai figli fino al limite configurato; la decisione di usarla resta
|
|
653
|
+
* sempre dell'agente che sta lavorando.
|
|
654
|
+
*/
|
|
655
|
+
function subTeamSpawner(opts, castle, mandate, iso, planStoreId) {
|
|
656
|
+
return async (specs) => {
|
|
657
|
+
const units = toUnits(specs, mandate);
|
|
658
|
+
if (!units.length)
|
|
659
|
+
return "team non avviato: nessuna unita' con un task riconoscibile";
|
|
660
|
+
try {
|
|
661
|
+
const report = await launchGranularKingdom({
|
|
662
|
+
harness: opts.harness,
|
|
663
|
+
kingdomId: opts.kingdomId,
|
|
664
|
+
castleSlug: castle.slug,
|
|
665
|
+
units,
|
|
666
|
+
signal: opts.signal,
|
|
667
|
+
confirm: opts.confirm,
|
|
668
|
+
ask: opts.ask,
|
|
669
|
+
concurrency: granularConcurrency(process.env),
|
|
670
|
+
// Lo slug composto dice all'host che questi sono sotto-collaboratori di
|
|
671
|
+
// questo castello, non nuovi vassalli dell'Imperatore.
|
|
672
|
+
onEvent: (id, event) => opts.onEvent?.(`${castle.slug}/${id}`, event),
|
|
673
|
+
onNotice: (text) => opts.onNotice?.(`[${castle.slug}] ${text}`),
|
|
674
|
+
...(iso.cwd ? { cwd: iso.cwd } : {}),
|
|
675
|
+
isolated: iso.isolated,
|
|
676
|
+
planStoreId,
|
|
677
|
+
...(opts.fileCoordination ? { fileCoordination: opts.fileCoordination } : {}),
|
|
678
|
+
depth: 2,
|
|
679
|
+
maxDepth: Number.isInteger(Number(process.env["TALOS_KINGDOM_MAX_DEPTH"]))
|
|
680
|
+
? Math.max(1, Math.min(5, Number(process.env["TALOS_KINGDOM_MAX_DEPTH"])))
|
|
681
|
+
: 3,
|
|
682
|
+
...(mandate ? { markCastle: mandate.castle } : {}),
|
|
683
|
+
});
|
|
684
|
+
return formatGranularReport(report);
|
|
685
|
+
}
|
|
686
|
+
catch (err) {
|
|
687
|
+
// Grafo malformato (ciclo, id duplicati): lo dice al vassallo, che puo'
|
|
688
|
+
// correggere, invece di far cadere il suo turno.
|
|
689
|
+
return `team non avviato: ${err.message}`;
|
|
690
|
+
}
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
async function runVassal(opts, provider, modelId, displayModel, castle, peers, iso, prerequisites = []) {
|
|
694
|
+
const { harness, kingdomId, signal, confirm, onEvent } = opts;
|
|
695
|
+
// Sessione (conversazione) dedicata al vassallo; store memoria CONDIVISO del
|
|
696
|
+
// regno (kingdomId) con id stanze namespaced sullo slug del castello.
|
|
697
|
+
const session = Session.create(harness.config.sessionDir, `${kingdomId}-${castle.slug}`);
|
|
698
|
+
const effort = ["low", "medium", "high", "max"].includes(String(castle.effort ?? "").toLowerCase())
|
|
699
|
+
? String(castle.effort).toLowerCase()
|
|
700
|
+
: "";
|
|
701
|
+
// Il piano resta quello di chi ha pianificato: le stanze che il collaboratore
|
|
702
|
+
// marca sono le stesse che l'utente vede sulla board.
|
|
703
|
+
// Gli host reali hanno sempre `harness.session`; i runner minimali/test e
|
|
704
|
+
// alcuni adapter legacy no. In quel caso il regno resta comunque uno scope
|
|
705
|
+
// stabile e condiviso invece di impedire lo spawn.
|
|
706
|
+
const planStoreId = harness.config.planStoreId ?? harness.session?.id ?? kingdomId;
|
|
707
|
+
const mandate = resolveMandate(harness.config.sessionDir, planStoreId, castle);
|
|
708
|
+
const runConfig = {
|
|
709
|
+
...harness.config,
|
|
710
|
+
model: modelId,
|
|
711
|
+
...(effort ? { effort } : {}),
|
|
712
|
+
roomStoreId: kingdomId,
|
|
713
|
+
roomNamespace: castle.slug,
|
|
714
|
+
planStoreId,
|
|
715
|
+
...(mandate ? { planCastle: mandate.castle, planTasks: mandate.rooms.map((room) => room.ref) } : {}),
|
|
716
|
+
// In modalita' isolata la working dir del vassallo e' il suo worktree.
|
|
717
|
+
...(iso.cwd ? { cwd: iso.cwd } : {}),
|
|
718
|
+
};
|
|
719
|
+
// Casella del vassallo: l'utente puo' scrivergli mentre lavora dalla sua
|
|
720
|
+
// scheda, e il messaggio entra nel contesto al primo confine sicuro come in
|
|
721
|
+
// chat principale. Senza, l'unico modo di correggerlo era fermare il regno.
|
|
722
|
+
const inbox = createUserInbox();
|
|
723
|
+
kingdomLive.register(kingdomId, castle.slug, inbox);
|
|
724
|
+
const workerTools = harness.tools.scoped(castle.tools);
|
|
725
|
+
for (const name of ["team_say", "team_inbox", "team_wait", "team_report", "vascend_status"])
|
|
726
|
+
workerTools.promote(name);
|
|
727
|
+
const deps = {
|
|
728
|
+
provider,
|
|
729
|
+
tools: workerTools,
|
|
730
|
+
session,
|
|
731
|
+
config: runConfig,
|
|
732
|
+
confirm,
|
|
733
|
+
ask: opts.ask,
|
|
734
|
+
host: undefined,
|
|
735
|
+
inbox,
|
|
736
|
+
...(opts.fileCoordination ? {
|
|
737
|
+
fileCoordination: withFileActor(opts.fileCoordination, fileActor(`${opts.fileCoordination.actor.id}:${castle.slug}`, castle.slug, "subagent")),
|
|
738
|
+
} : {}),
|
|
739
|
+
// Delega di secondo livello: un castello grande si gestisce formando un team
|
|
740
|
+
// sulle proprie stanze. Prima questo campo mancava, e kingdoms_warm dentro
|
|
741
|
+
// un vassallo rispondeva "non disponibile": la gerarchia era ferma a 1.
|
|
742
|
+
spawnKingdom: subTeamSpawner({ ...opts, harness: { ...harness, config: runConfig, tools: workerTools } }, castle, mandate, iso, planStoreId),
|
|
743
|
+
// isolated abilita il git nel vassallo (worktree proprio); altrimenti il
|
|
744
|
+
// bash tool blocca il git che muta (working dir condivisa).
|
|
745
|
+
kingdom: { id: kingdomId, self: castle.slug, isolated: iso.isolated, peers },
|
|
746
|
+
};
|
|
747
|
+
let summary = "";
|
|
748
|
+
const artifacts = new Map();
|
|
749
|
+
const reportArtifacts = () => {
|
|
750
|
+
const store = ToolOutputStore.open(harness.config.sessionDir, kingdomId);
|
|
751
|
+
const entry = store.put("report-" + session.id, castle.slug + " report", summary.trim());
|
|
752
|
+
if (entry?.sha256)
|
|
753
|
+
artifacts.set(kingdomId + ":" + entry.id, { id: entry.id, scope: kingdomId, name: entry.name, sha256: entry.sha256, chars: entry.chars });
|
|
754
|
+
return [...artifacts.values()];
|
|
755
|
+
};
|
|
756
|
+
let runError = "";
|
|
757
|
+
let completed = false;
|
|
758
|
+
const sink = (event) => {
|
|
759
|
+
if (event.type === "tool_result") {
|
|
760
|
+
const ref = artifactReference(event.result);
|
|
761
|
+
if (ref) {
|
|
762
|
+
artifacts.set(ref.scope + ":" + ref.id, ref);
|
|
763
|
+
if (artifacts.size > 64)
|
|
764
|
+
artifacts.delete(artifacts.keys().next().value);
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
if (event.type === "text")
|
|
768
|
+
summary += event.delta;
|
|
769
|
+
if (event.type === "error")
|
|
770
|
+
runError = event.message;
|
|
771
|
+
if (event.type === "done")
|
|
772
|
+
completed = true;
|
|
773
|
+
onEvent?.(castle.slug, event);
|
|
774
|
+
};
|
|
775
|
+
try {
|
|
776
|
+
const role = castle.role?.trim() || "collaboratore";
|
|
777
|
+
const parent = castle.parent?.trim() || "orchestratore";
|
|
778
|
+
const instructions = (castle.area?.length ? `\nAREA_ASSEGNATA: ${castle.area.join(", ")}. Coordina modifiche fuori area prima di eseguirle.\n` : "") + (castle.instructions?.trim()
|
|
779
|
+
? `\nISTRUZIONI_AGGIUNTIVE\n${castle.instructions.trim()}\n\n`
|
|
780
|
+
: "\n");
|
|
781
|
+
// Con un castello assegnato l'obiettivo si DERIVA dal piano: nessuno deve
|
|
782
|
+
// riscrivere in prosa quello che le stanze dicono gia'.
|
|
783
|
+
const goal = castle.goal?.trim() || (mandate ? mandateGoal(mandate) : "");
|
|
784
|
+
const input = vassalSteer(castle.slug, peers, castle.after ?? [], { role, parent }, { isolated: iso.isolated, base: iso.base }, mandate ? formatMandate(mandate, true) : "") + instructions + (prerequisites.length ? "\nPREREQUISITI_COMPLETATI (risultati da verificare)\n"
|
|
785
|
+
+ prerequisites.map((report) => `[${report.slug}] task=${(report.taskRefs ?? []).join(",")}\n`
|
|
786
|
+
+ (report.artifacts ?? []).slice(-4).map((ref) => `output_page id="${ref.id}" scope="${ref.scope}" sha256=${ref.sha256}`).join("\n")
|
|
787
|
+
+ "\n" + report.summary.slice(0, 1600)).join("\n").slice(0, 10000) + "\n\n" : "") + goal;
|
|
788
|
+
await runTurn(deps, input, sink, signal);
|
|
789
|
+
const rooms = countRooms(harness.config.sessionDir, kingdomId, castle.slug);
|
|
790
|
+
const completion = mandateCompletion(harness.config.sessionDir, planStoreId, mandate);
|
|
791
|
+
const ok = !signal.aborted && !runError && completed && completion.ok;
|
|
792
|
+
return {
|
|
793
|
+
slug: castle.slug,
|
|
794
|
+
ok,
|
|
795
|
+
summary: summary.trim(),
|
|
796
|
+
artifacts: reportArtifacts(),
|
|
797
|
+
rooms,
|
|
798
|
+
model: displayModel,
|
|
799
|
+
role,
|
|
800
|
+
parent,
|
|
801
|
+
...(castle.castle ? { workstreamId: castle.castle } : {}),
|
|
802
|
+
...(castle.tasks?.length
|
|
803
|
+
? { taskRefs: [...castle.tasks] }
|
|
804
|
+
: mandate?.rooms.length ? { taskRefs: mandate.rooms.map((room) => room.ref) } : {}),
|
|
805
|
+
...(!ok ? {
|
|
806
|
+
error: signal.aborted
|
|
807
|
+
? "collaboratore arrestato"
|
|
808
|
+
: runError || completion.error || "task non completato",
|
|
809
|
+
} : {}),
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
catch (err) {
|
|
813
|
+
return {
|
|
814
|
+
slug: castle.slug,
|
|
815
|
+
ok: false,
|
|
816
|
+
summary: summary.trim(),
|
|
817
|
+
artifacts: reportArtifacts(),
|
|
818
|
+
rooms: 0,
|
|
819
|
+
model: displayModel,
|
|
820
|
+
role: castle.role?.trim() || "collaboratore",
|
|
821
|
+
parent: castle.parent?.trim() || "orchestratore",
|
|
822
|
+
...(castle.castle ? { workstreamId: castle.castle } : {}),
|
|
823
|
+
...(castle.tasks?.length ? { taskRefs: [...castle.tasks] } : {}),
|
|
824
|
+
error: err.message,
|
|
825
|
+
};
|
|
826
|
+
}
|
|
827
|
+
finally {
|
|
828
|
+
deps.fileCoordination?.hub.clearActor(deps.fileCoordination.actor.id);
|
|
829
|
+
// Il collaboratore non c'e' piu': la UI deve saperlo subito, altrimenti
|
|
830
|
+
// continuerebbe a offrire un campo di scrittura che non consegna nulla.
|
|
831
|
+
kingdomLive.release(kingdomId, castle.slug);
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
function mandateCompletion(sessionDir, planStoreId, mandate) {
|
|
835
|
+
if (!mandate)
|
|
836
|
+
return { ok: true };
|
|
837
|
+
try {
|
|
838
|
+
const current = VascendPlanStore.open(sessionDir, planStoreId).castle(mandate.castle);
|
|
839
|
+
if (!current)
|
|
840
|
+
return { ok: false, error: `gruppo ${mandate.castle} non piu' disponibile` };
|
|
841
|
+
const refs = new Set(mandate.rooms.map((room) => room.ref.toLowerCase()));
|
|
842
|
+
const assigned = current.tasks.filter((task) => refs.has(task.id.toLowerCase()));
|
|
843
|
+
const failed = assigned.filter((task) => task.status === "failed");
|
|
844
|
+
const open = assigned.filter((task) => task.status !== "completed" && task.status !== "failed");
|
|
845
|
+
if (failed.length) {
|
|
846
|
+
return { ok: false, error: `task falliti: ${failed.map((task) => task.id).join(", ")}` };
|
|
847
|
+
}
|
|
848
|
+
if (assigned.length !== refs.size || open.length) {
|
|
849
|
+
const pending = open.map((task) => `${task.id} (${task.status})`);
|
|
850
|
+
return {
|
|
851
|
+
ok: false,
|
|
852
|
+
error: `task non conclusi: ${pending.length ? pending.join(", ") : "assegnazione incompleta"}`,
|
|
853
|
+
};
|
|
854
|
+
}
|
|
855
|
+
return { ok: true };
|
|
856
|
+
}
|
|
857
|
+
catch (err) {
|
|
858
|
+
return { ok: false, error: `verifica task fallita: ${err.message}` };
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
// Conta le stanze (livello 0) di un castello nello store condiviso del regno.
|
|
862
|
+
function countRooms(sessionDir, kingdomId, slug) {
|
|
863
|
+
try {
|
|
864
|
+
const mem = RoomMemory.open(sessionDir, kingdomId);
|
|
865
|
+
return mem.all().filter((r) => r.level === 0 && r.room.startsWith(`${slug}-`)).length;
|
|
866
|
+
}
|
|
867
|
+
catch {
|
|
868
|
+
return 0;
|
|
869
|
+
}
|
|
870
|
+
}
|