comisai 1.0.36 → 1.0.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/node_modules/@comis/agent/dist/background/auto-background-middleware.js +9 -0
- package/node_modules/@comis/agent/dist/background/background-task-manager.d.ts +22 -2
- package/node_modules/@comis/agent/dist/background/background-task-manager.js +48 -41
- package/node_modules/@comis/agent/dist/background/background-task-persistence.js +28 -5
- package/node_modules/@comis/agent/dist/background/background-task-types.d.ts +49 -0
- package/node_modules/@comis/agent/dist/background/completion-dispatcher.d.ts +130 -0
- package/node_modules/@comis/agent/dist/background/completion-dispatcher.js +215 -0
- package/node_modules/@comis/agent/dist/background/completion-runner.d.ts +10 -1
- package/node_modules/@comis/agent/dist/background/completion-runner.js +98 -15
- package/node_modules/@comis/agent/dist/background/index.d.ts +6 -1
- package/node_modules/@comis/agent/dist/background/index.js +2 -0
- package/node_modules/@comis/agent/dist/background/session-resolver.d.ts +85 -0
- package/node_modules/@comis/agent/dist/background/session-resolver.js +78 -0
- package/node_modules/@comis/agent/dist/bootstrap/sections/messaging-sections.js +1 -0
- package/node_modules/@comis/agent/dist/bootstrap/sections/tool-descriptions.js +3 -3
- package/node_modules/@comis/agent/dist/bootstrap/sections/tooling-sections.d.ts +30 -2
- package/node_modules/@comis/agent/dist/bootstrap/sections/tooling-sections.js +51 -2
- package/node_modules/@comis/agent/dist/bootstrap/system-prompt-assembler.d.ts +22 -0
- package/node_modules/@comis/agent/dist/bootstrap/system-prompt-assembler.js +2 -2
- package/node_modules/@comis/agent/dist/bridge/bridge-event-handlers.d.ts +1 -5
- package/node_modules/@comis/agent/dist/bridge/bridge-event-handlers.js +2 -14
- package/node_modules/@comis/agent/dist/bridge/bridge-metrics.d.ts +26 -0
- package/node_modules/@comis/agent/dist/bridge/bridge-metrics.js +3 -0
- package/node_modules/@comis/agent/dist/bridge/pi-event-bridge.d.ts +9 -0
- package/node_modules/@comis/agent/dist/bridge/pi-event-bridge.js +73 -2
- package/node_modules/@comis/agent/dist/context-engine/signature-surrogate-guard.d.ts +10 -10
- package/node_modules/@comis/agent/dist/context-engine/signature-surrogate-guard.js +14 -14
- package/node_modules/@comis/agent/dist/context-engine/thinking-block-cleaner.d.ts +11 -13
- package/node_modules/@comis/agent/dist/context-engine/thinking-block-cleaner.js +14 -15
- package/node_modules/@comis/agent/dist/executor/capability-index-context.d.ts +72 -0
- package/node_modules/@comis/agent/dist/executor/capability-index-context.js +329 -0
- package/node_modules/@comis/agent/dist/executor/drain-helper.d.ts +122 -0
- package/node_modules/@comis/agent/dist/executor/drain-helper.js +173 -0
- package/node_modules/@comis/agent/dist/executor/error-classifier.js +2 -2
- package/node_modules/@comis/agent/dist/executor/executor-post-execution.d.ts +48 -4
- package/node_modules/@comis/agent/dist/executor/executor-post-execution.js +134 -31
- package/node_modules/@comis/agent/dist/executor/executor-prompt-runner.d.ts +7 -0
- package/node_modules/@comis/agent/dist/executor/executor-prompt-runner.js +25 -4
- package/node_modules/@comis/agent/dist/executor/executor-tool-assembly.d.ts +18 -1
- package/node_modules/@comis/agent/dist/executor/executor-tool-assembly.js +19 -16
- package/node_modules/@comis/agent/dist/executor/jit-guide-injector.d.ts +11 -2
- package/node_modules/@comis/agent/dist/executor/jit-guide-injector.js +16 -2
- package/node_modules/@comis/agent/dist/executor/pi-executor.d.ts +8 -2
- package/node_modules/@comis/agent/dist/executor/pi-executor.js +25 -12
- package/node_modules/@comis/agent/dist/executor/prompt-assembly.d.ts +9 -1
- package/node_modules/@comis/agent/dist/executor/prompt-assembly.js +15 -1
- package/node_modules/@comis/agent/dist/executor/tool-deferral.d.ts +18 -27
- package/node_modules/@comis/agent/dist/executor/tool-deferral.js +29 -38
- package/node_modules/@comis/agent/dist/model/model-registry-adapter.js +1 -1
- package/node_modules/@comis/agent/dist/model/model-scanner.js +1 -1
- package/node_modules/@comis/agent/dist/safety/tool-retry-breaker.d.ts +11 -1
- package/node_modules/@comis/agent/dist/safety/tool-retry-breaker.js +19 -22
- package/node_modules/@comis/agent/dist/session/comis-session-manager.d.ts +16 -2
- package/node_modules/@comis/agent/dist/spawn/pi-mono-adapters.d.ts +1 -1
- package/node_modules/@comis/agent/dist/spawn/pi-mono-adapters.js +5 -5
- package/node_modules/@comis/agent/dist/workspace/data-env.d.ts +38 -0
- package/node_modules/@comis/agent/dist/workspace/data-env.js +56 -0
- package/node_modules/@comis/agent/dist/workspace/index.d.ts +1 -0
- package/node_modules/@comis/agent/dist/workspace/index.js +1 -0
- package/node_modules/@comis/agent/dist/workspace/templates.js +5 -1
- package/node_modules/@comis/agent/package.json +1 -1
- package/node_modules/@comis/channels/dist/index.d.ts +1 -1
- package/node_modules/@comis/channels/dist/index.js +1 -1
- package/node_modules/@comis/channels/dist/shared/channel-manager.d.ts +9 -3
- package/node_modules/@comis/channels/dist/shared/inbound-gate.d.ts +1 -1
- package/node_modules/@comis/channels/dist/shared/inbound-gate.js +22 -7
- package/node_modules/@comis/channels/dist/shared/inbound-pipeline.d.ts +10 -3
- package/node_modules/@comis/channels/dist/shared/inbound-route.d.ts +1 -1
- package/node_modules/@comis/channels/dist/shared/inbound-route.js +13 -2
- package/node_modules/@comis/channels/dist/shared/response-filter.d.ts +11 -24
- package/node_modules/@comis/channels/dist/shared/response-filter.js +25 -53
- package/node_modules/@comis/channels/package.json +1 -1
- package/node_modules/@comis/cli/dist/commands/providers.d.ts +1 -2
- package/node_modules/@comis/cli/dist/commands/providers.js +5 -6
- package/node_modules/@comis/cli/package.json +1 -1
- package/node_modules/@comis/core/dist/config/field-metadata.js +2 -0
- package/node_modules/@comis/core/dist/config/immutable-keys.js +4 -1
- package/node_modules/@comis/core/dist/config/index.d.ts +4 -0
- package/node_modules/@comis/core/dist/config/index.js +2 -0
- package/node_modules/@comis/core/dist/config/schema-agent.d.ts +0 -792
- package/node_modules/@comis/core/dist/config/schema-approvals.d.ts +0 -14
- package/node_modules/@comis/core/dist/config/schema-auto-reply-engine.d.ts +0 -6
- package/node_modules/@comis/core/dist/config/schema-background-tasks.d.ts +0 -12
- package/node_modules/@comis/core/dist/config/schema-browser.d.ts +0 -18
- package/node_modules/@comis/core/dist/config/schema-channel.d.ts +0 -158
- package/node_modules/@comis/core/dist/config/schema-coalescer.d.ts +0 -5
- package/node_modules/@comis/core/dist/config/schema-daemon.d.ts +0 -32
- package/node_modules/@comis/core/dist/config/schema-delivery.d.ts +0 -18
- package/node_modules/@comis/core/dist/config/schema-documentation.d.ts +0 -12
- package/node_modules/@comis/core/dist/config/schema-embedding.d.ts +0 -20
- package/node_modules/@comis/core/dist/config/schema-envelope.d.ts +0 -15
- package/node_modules/@comis/core/dist/config/schema-gateway.d.ts +0 -37
- package/node_modules/@comis/core/dist/config/schema-gemini-cache.d.ts +0 -2
- package/node_modules/@comis/core/dist/config/schema-integrations.d.ts +0 -318
- package/node_modules/@comis/core/dist/config/schema-lifecycle-reactions.d.ts +0 -18
- package/node_modules/@comis/core/dist/config/schema-memory-review.d.ts +0 -7
- package/node_modules/@comis/core/dist/config/schema-memory.d.ts +0 -16
- package/node_modules/@comis/core/dist/config/schema-messages.d.ts +0 -8
- package/node_modules/@comis/core/dist/config/schema-models.d.ts +0 -15
- package/node_modules/@comis/core/dist/config/schema-notification.d.ts +0 -5
- package/node_modules/@comis/core/dist/config/schema-oauth.d.ts +0 -5
- package/node_modules/@comis/core/dist/config/schema-observability.d.ts +0 -38
- package/node_modules/@comis/core/dist/config/schema-output-retention.d.ts +34 -0
- package/node_modules/@comis/core/dist/config/schema-output-retention.js +48 -0
- package/node_modules/@comis/core/dist/config/schema-plugins.d.ts +0 -8
- package/node_modules/@comis/core/dist/config/schema-providers.d.ts +0 -64
- package/node_modules/@comis/core/dist/config/schema-queue.d.ts +0 -58
- package/node_modules/@comis/core/dist/config/schema-response-prefix.d.ts +0 -2
- package/node_modules/@comis/core/dist/config/schema-retry.d.ts +0 -6
- package/node_modules/@comis/core/dist/config/schema-scheduler.d.ts +0 -39
- package/node_modules/@comis/core/dist/config/schema-secrets.d.ts +0 -3
- package/node_modules/@comis/core/dist/config/schema-security.d.ts +0 -18
- package/node_modules/@comis/core/dist/config/schema-send-policy.d.ts +0 -13
- package/node_modules/@comis/core/dist/config/schema-sender-trust-display.d.ts +0 -5
- package/node_modules/@comis/core/dist/config/schema-serializer.js +2 -0
- package/node_modules/@comis/core/dist/config/schema-skills.d.ts +0 -61
- package/node_modules/@comis/core/dist/config/schema-streaming.d.ts +0 -38
- package/node_modules/@comis/core/dist/config/schema-telegram-file-guard.d.ts +0 -3
- package/node_modules/@comis/core/dist/config/schema-tooling.d.ts +87 -0
- package/node_modules/@comis/core/dist/config/schema-tooling.js +152 -0
- package/node_modules/@comis/core/dist/config/schema-verbosity.d.ts +0 -12
- package/node_modules/@comis/core/dist/config/schema-webhooks.d.ts +0 -40
- package/node_modules/@comis/core/dist/config/schema.d.ts +41 -38
- package/node_modules/@comis/core/dist/config/schema.js +6 -0
- package/node_modules/@comis/core/dist/context/context.d.ts +0 -4
- package/node_modules/@comis/core/dist/domain/approval-request.d.ts +0 -17
- package/node_modules/@comis/core/dist/domain/background-task-origin.d.ts +0 -10
- package/node_modules/@comis/core/dist/domain/delivery-origin.d.ts +0 -5
- package/node_modules/@comis/core/dist/domain/execution-graph.d.ts +0 -48
- package/node_modules/@comis/core/dist/domain/memory-entry.d.ts +0 -3
- package/node_modules/@comis/core/dist/domain/model-compat.d.ts +0 -4
- package/node_modules/@comis/core/dist/domain/normalized-message.d.ts +0 -15
- package/node_modules/@comis/core/dist/domain/provider-capabilities.d.ts +0 -6
- package/node_modules/@comis/core/dist/domain/rich-message.d.ts +0 -14
- package/node_modules/@comis/core/dist/domain/subagent-context-config.d.ts +0 -22
- package/node_modules/@comis/core/dist/domain/subagent-context-types.d.ts +0 -8
- package/node_modules/@comis/core/dist/event-bus/events-agent.d.ts +31 -0
- package/node_modules/@comis/core/dist/event-bus/events-infra.d.ts +5 -0
- package/node_modules/@comis/core/dist/exports/config.d.ts +2 -2
- package/node_modules/@comis/core/dist/exports/config.js +3 -1
- package/node_modules/@comis/core/dist/exports/hooks.d.ts +1 -1
- package/node_modules/@comis/core/dist/exports/ports.d.ts +2 -2
- package/node_modules/@comis/core/dist/exports/ports.js +1 -1
- package/node_modules/@comis/core/dist/ports/channel-plugin.d.ts +0 -13
- package/node_modules/@comis/core/dist/ports/index.d.ts +2 -0
- package/node_modules/@comis/core/dist/ports/index.js +4 -0
- package/node_modules/@comis/core/dist/ports/no-op-tool-capability.d.ts +30 -0
- package/node_modules/@comis/core/dist/ports/no-op-tool-capability.js +47 -0
- package/node_modules/@comis/core/dist/ports/tool-capability.d.ts +165 -0
- package/node_modules/@comis/core/dist/ports/tool-capability.js +15 -0
- package/node_modules/@comis/core/dist/security/audit.d.ts +0 -11
- package/node_modules/@comis/core/dist/tool-metadata.d.ts +21 -1
- package/node_modules/@comis/core/dist/tool-metadata.js +1 -1
- package/node_modules/@comis/core/package.json +1 -1
- package/node_modules/@comis/daemon/bundled-skills/skill-creator/scripts/validate-skill.py +1 -1
- package/node_modules/@comis/daemon/dist/daemon.js +89 -14
- package/node_modules/@comis/daemon/dist/rpc/agent-inline-workspace.d.ts +1 -1
- package/node_modules/@comis/daemon/dist/rpc/agent-inline-workspace.js +1 -1
- package/node_modules/@comis/daemon/dist/rpc/builtin-provider-guard.js +2 -2
- package/node_modules/@comis/daemon/dist/rpc/credential-resolver.js +1 -1
- package/node_modules/@comis/daemon/dist/rpc/model-handlers.d.ts +1 -1
- package/node_modules/@comis/daemon/dist/rpc/model-handlers.js +2 -2
- package/node_modules/@comis/daemon/dist/sub-agent-runner.d.ts +18 -0
- package/node_modules/@comis/daemon/dist/sub-agent-runner.js +41 -9
- package/node_modules/@comis/daemon/dist/wiring/index.d.ts +2 -0
- package/node_modules/@comis/daemon/dist/wiring/index.js +1 -0
- package/node_modules/@comis/daemon/dist/wiring/setup-agents.d.ts +36 -2
- package/node_modules/@comis/daemon/dist/wiring/setup-agents.js +45 -8
- package/node_modules/@comis/daemon/dist/wiring/setup-background-completion-runner.d.ts +28 -9
- package/node_modules/@comis/daemon/dist/wiring/setup-background-completion-runner.js +36 -9
- package/node_modules/@comis/daemon/dist/wiring/setup-background-tasks.js +2 -2
- package/node_modules/@comis/daemon/dist/wiring/setup-channels.d.ts +9 -2
- package/node_modules/@comis/daemon/dist/wiring/setup-channels.js +15 -9
- package/node_modules/@comis/daemon/dist/wiring/setup-cross-session.d.ts +20 -5
- package/node_modules/@comis/daemon/dist/wiring/setup-cross-session.js +20 -15
- package/node_modules/@comis/daemon/dist/wiring/setup-delivery.js +14 -2
- package/node_modules/@comis/daemon/dist/wiring/setup-gateway.d.ts +4 -6
- package/node_modules/@comis/daemon/dist/wiring/setup-gateway.js +3 -5
- package/node_modules/@comis/daemon/dist/wiring/setup-heartbeat.d.ts +20 -5
- package/node_modules/@comis/daemon/dist/wiring/setup-heartbeat.js +11 -2
- package/node_modules/@comis/daemon/dist/wiring/setup-output-retention.d.ts +89 -0
- package/node_modules/@comis/daemon/dist/wiring/setup-output-retention.js +212 -0
- package/node_modules/@comis/daemon/dist/wiring/setup-tools.d.ts +18 -4
- package/node_modules/@comis/daemon/dist/wiring/setup-tools.js +29 -10
- package/node_modules/@comis/daemon/dist/wiring/tool-capability-adapter.d.ts +75 -0
- package/node_modules/@comis/daemon/dist/wiring/tool-capability-adapter.js +253 -0
- package/node_modules/@comis/daemon/package.json +1 -1
- package/node_modules/@comis/gateway/dist/webhook/webhook-endpoint.d.ts +0 -4
- package/node_modules/@comis/gateway/package.json +1 -1
- package/node_modules/@comis/infra/package.json +1 -1
- package/node_modules/@comis/memory/package.json +1 -1
- package/node_modules/@comis/scheduler/dist/cron/cron-types.d.ts +0 -42
- package/node_modules/@comis/scheduler/dist/heartbeat/agent-heartbeat-source.d.ts +29 -8
- package/node_modules/@comis/scheduler/dist/heartbeat/agent-heartbeat-source.js +19 -7
- package/node_modules/@comis/scheduler/dist/system-events/system-event-types.d.ts +0 -3
- package/node_modules/@comis/scheduler/dist/tasks/task-types.d.ts +0 -17
- package/node_modules/@comis/scheduler/package.json +1 -1
- package/node_modules/@comis/shared/dist/index.d.ts +3 -0
- package/node_modules/@comis/shared/dist/index.js +4 -0
- package/node_modules/@comis/shared/dist/mcp-tool-name.d.ts +78 -0
- package/node_modules/@comis/shared/dist/mcp-tool-name.js +92 -0
- package/node_modules/@comis/shared/dist/silent-tokens.d.ts +38 -0
- package/node_modules/@comis/shared/dist/silent-tokens.js +51 -0
- package/node_modules/@comis/shared/dist/visible-delivery.d.ts +28 -0
- package/node_modules/@comis/shared/dist/visible-delivery.js +16 -0
- package/node_modules/@comis/shared/package.json +1 -1
- package/node_modules/@comis/skills/dist/bridge/mcp-tool-bridge.d.ts +2 -13
- package/node_modules/@comis/skills/dist/bridge/mcp-tool-bridge.js +3 -21
- package/node_modules/@comis/skills/dist/bridge/tool-metadata-enforcement.js +1 -1
- package/node_modules/@comis/skills/dist/bridge/tool-metadata-registry.js +4 -4
- package/node_modules/@comis/skills/dist/builtin/exec-tool.d.ts +55 -9
- package/node_modules/@comis/skills/dist/builtin/exec-tool.js +383 -19
- package/node_modules/@comis/skills/dist/builtin/install-detour.d.ts +67 -0
- package/node_modules/@comis/skills/dist/builtin/install-detour.js +342 -0
- package/node_modules/@comis/skills/dist/builtin/platform/admin-manage-factory.js +5 -5
- package/node_modules/@comis/skills/dist/builtin/platform/agents-manage-tool.d.ts +2 -2
- package/node_modules/@comis/skills/dist/builtin/platform/agents-manage-tool.js +2 -2
- package/node_modules/@comis/skills/dist/builtin/platform/message-tool.js +18 -0
- package/node_modules/@comis/skills/dist/builtin/platform/messaging-factory.d.ts +18 -1
- package/node_modules/@comis/skills/dist/builtin/platform/messaging-factory.js +18 -2
- package/node_modules/@comis/skills/dist/builtin/platform/models-manage-tool.js +3 -3
- package/node_modules/@comis/skills/dist/builtin/process-registry.d.ts +14 -0
- package/node_modules/@comis/skills/dist/builtin/process-tool.d.ts +24 -4
- package/node_modules/@comis/skills/dist/builtin/process-tool.js +25 -7
- package/node_modules/@comis/skills/dist/builtin/sandbox/bwrap-provider.d.ts +1 -1
- package/node_modules/@comis/skills/dist/builtin/sandbox/bwrap-provider.js +9 -0
- package/node_modules/@comis/skills/dist/index.d.ts +4 -1
- package/node_modules/@comis/skills/dist/index.js +3 -1
- package/node_modules/@comis/skills/dist/manifest/capability-parser.d.ts +44 -0
- package/node_modules/@comis/skills/dist/manifest/capability-parser.js +68 -0
- package/node_modules/@comis/skills/dist/manifest/schema.d.ts +44 -37
- package/node_modules/@comis/skills/dist/manifest/schema.js +35 -0
- package/node_modules/@comis/skills/dist/registry/discovery.d.ts +8 -0
- package/node_modules/@comis/skills/dist/registry/discovery.js +10 -3
- package/node_modules/@comis/skills/dist/registry/skill-registry.d.ts +45 -1
- package/node_modules/@comis/skills/dist/registry/skill-registry.js +70 -7
- package/node_modules/@comis/skills/package.json +1 -1
- package/node_modules/@comis/web/package.json +1 -1
- package/package.json +21 -21
|
@@ -27,6 +27,15 @@ import { suppressError } from "@comis/shared";
|
|
|
27
27
|
* If promotion fails (concurrency limit), awaits the tool normally (foreground fallback).
|
|
28
28
|
*/
|
|
29
29
|
export function wrapToolForAutoBackground(tool, manager, config, notifyFn, originResolver) {
|
|
30
|
+
// `exec` opts out of the generic auto-background wrapper to enforce
|
|
31
|
+
// single-owner backgrounding. The exec-tool's own internal escalation path
|
|
32
|
+
// (packages/skills/src/builtin/exec-tool.ts:613-668) is the SOLE
|
|
33
|
+
// backgrounding owner for `exec`; the generic timeout-based wrapper would
|
|
34
|
+
// double-promote. Hardcoded literal — does NOT modify config.excludeTools
|
|
35
|
+
// so operator-set exclusions remain unchanged.
|
|
36
|
+
if (tool.name === "exec") {
|
|
37
|
+
return tool;
|
|
38
|
+
}
|
|
30
39
|
if (config.excludeTools.includes(tool.name)) {
|
|
31
40
|
return tool;
|
|
32
41
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type Result } from "@comis/shared";
|
|
2
2
|
import type { TypedEventBus } from "@comis/core";
|
|
3
|
-
import type { BackgroundTask, BackgroundTaskOrigin } from "./background-task-types.js";
|
|
3
|
+
import type { BackgroundTask, BackgroundTaskOrigin, BackgroundSessionState, BackgroundTaskNotificationPolicy } from "./background-task-types.js";
|
|
4
4
|
/** Notification callback fired when background task completes or fails. */
|
|
5
5
|
export type NotifyFn = (opts: {
|
|
6
6
|
agentId: string;
|
|
@@ -21,8 +21,21 @@ export interface BackgroundTaskManagerOpts {
|
|
|
21
21
|
maxBackgroundDurationMs?: number;
|
|
22
22
|
}
|
|
23
23
|
export interface BackgroundTaskManager {
|
|
24
|
-
promote(toolName: string, promise: Promise<unknown>, ac: AbortController, origin: BackgroundTaskOrigin): Result<string, Error>;
|
|
24
|
+
promote(toolName: string, promise: Promise<unknown>, ac: AbortController, origin: BackgroundTaskOrigin, notificationPolicy?: BackgroundTaskNotificationPolicy): Result<string, Error>;
|
|
25
|
+
/**
|
|
26
|
+
* Mark a task as completed.
|
|
27
|
+
*
|
|
28
|
+
* The legacy `notifyFn` argument is preserved for backward compatibility but
|
|
29
|
+
* unused — the completion-dispatcher subscribes to the
|
|
30
|
+
* `background_task:completed` event emitted here and decides whether to fire
|
|
31
|
+
* the user-visible fallback notification. Single-owner contract eliminates
|
|
32
|
+
* double-notify.
|
|
33
|
+
*/
|
|
25
34
|
complete(taskId: string, result: unknown, notifyFn?: NotifyFn): void;
|
|
35
|
+
/**
|
|
36
|
+
* Mark a task as failed. See `complete` for the single-owner note — the
|
|
37
|
+
* `notifyFn` argument is unused; the dispatcher routes notification.
|
|
38
|
+
*/
|
|
26
39
|
fail(taskId: string, error: unknown, notifyFn?: NotifyFn): void;
|
|
27
40
|
cancel(taskId: string): Result<void, Error>;
|
|
28
41
|
getTask(taskId: string): BackgroundTask | undefined;
|
|
@@ -30,5 +43,12 @@ export interface BackgroundTaskManager {
|
|
|
30
43
|
getAllTasks(): BackgroundTask[];
|
|
31
44
|
recoverOnStartup(): void;
|
|
32
45
|
cleanup(maxAgeMs?: number): void;
|
|
46
|
+
/**
|
|
47
|
+
* Atomically transition the in-memory task's dispatchState AND persist.
|
|
48
|
+
* Returns true on success; false if task does not exist. The dispatcher
|
|
49
|
+
* calls this from its handler so SIGKILL-recovery preserves the recovered
|
|
50
|
+
* state across daemon restart.
|
|
51
|
+
*/
|
|
52
|
+
transitionDispatchState(taskId: string, next: BackgroundSessionState): boolean;
|
|
33
53
|
}
|
|
34
54
|
export declare function createBackgroundTaskManager(opts: BackgroundTaskManagerOpts): BackgroundTaskManager;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* @module
|
|
9
9
|
*/
|
|
10
10
|
import { randomUUID } from "node:crypto";
|
|
11
|
-
import { ok, err
|
|
11
|
+
import { ok, err } from "@comis/shared";
|
|
12
12
|
import { persistTaskSync, recoverTasks, removeTaskFile } from "./background-task-persistence.js";
|
|
13
13
|
const MAX_RESULT_CHARS = 102_400; // 100KB
|
|
14
14
|
export function createBackgroundTaskManager(opts) {
|
|
@@ -35,7 +35,7 @@ export function createBackgroundTaskManager(opts) {
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
const manager = {
|
|
38
|
-
promote(toolName, promise, ac, origin) {
|
|
38
|
+
promote(toolName, promise, ac, origin, notificationPolicy) {
|
|
39
39
|
// Reject calls with missing/invalid origin (no silent fallback).
|
|
40
40
|
if (!origin || typeof origin !== "object") {
|
|
41
41
|
return err(new Error("BackgroundTaskOrigin is required (received undefined or non-object)"));
|
|
@@ -69,6 +69,11 @@ export function createBackgroundTaskManager(opts) {
|
|
|
69
69
|
status: "running",
|
|
70
70
|
startedAt: Date.now(),
|
|
71
71
|
origin,
|
|
72
|
+
// Seed the dispatch state machine. Default policy is "deferred" —
|
|
73
|
+
// the dispatcher inspects dispatchState before firing fallback notify
|
|
74
|
+
// (at-most-once).
|
|
75
|
+
notificationPolicy: notificationPolicy ?? "deferred",
|
|
76
|
+
dispatchState: "pending",
|
|
72
77
|
_promise: promise,
|
|
73
78
|
_abortController: ac,
|
|
74
79
|
};
|
|
@@ -92,7 +97,7 @@ export function createBackgroundTaskManager(opts) {
|
|
|
92
97
|
});
|
|
93
98
|
return ok(taskId);
|
|
94
99
|
},
|
|
95
|
-
complete(taskId, result,
|
|
100
|
+
complete(taskId, result, _notifyFn) {
|
|
96
101
|
const task = tasks.get(taskId);
|
|
97
102
|
if (!task || task.status !== "running")
|
|
98
103
|
return;
|
|
@@ -112,16 +117,14 @@ export function createBackgroundTaskManager(opts) {
|
|
|
112
117
|
origin: task.origin,
|
|
113
118
|
timestamp: Date.now(),
|
|
114
119
|
});
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}), "background task completion notification");
|
|
122
|
-
}
|
|
120
|
+
// Notification routing lives in the completion-dispatcher (subscribed
|
|
121
|
+
// to background_task:completed above). The legacy `notifyFn` argument
|
|
122
|
+
// is kept for backward compatibility but unused here — the dispatcher
|
|
123
|
+
// inspects task.dispatchState before firing the user-visible fallback,
|
|
124
|
+
// and the runner skips when state is "notified" (single-owner contract,
|
|
125
|
+
// zero spurious outbound).
|
|
123
126
|
},
|
|
124
|
-
fail(taskId, error,
|
|
127
|
+
fail(taskId, error, _notifyFn) {
|
|
125
128
|
const task = tasks.get(taskId);
|
|
126
129
|
if (!task || task.status !== "running")
|
|
127
130
|
return;
|
|
@@ -142,14 +145,7 @@ export function createBackgroundTaskManager(opts) {
|
|
|
142
145
|
origin: task.origin,
|
|
143
146
|
timestamp: Date.now(),
|
|
144
147
|
});
|
|
145
|
-
|
|
146
|
-
suppressError(notifyFn({
|
|
147
|
-
agentId: task.origin.agentId,
|
|
148
|
-
message: `Background task "${task.toolName}" failed: ${task.error}. Task ID: ${taskId}`,
|
|
149
|
-
priority: "normal",
|
|
150
|
-
origin: "background_task",
|
|
151
|
-
}), "background task failure notification");
|
|
152
|
-
}
|
|
148
|
+
// See complete() above — notifyFn arg is unused; dispatcher owns routing.
|
|
153
149
|
},
|
|
154
150
|
cancel(taskId) {
|
|
155
151
|
const task = tasks.get(taskId);
|
|
@@ -185,24 +181,29 @@ export function createBackgroundTaskManager(opts) {
|
|
|
185
181
|
recoverOnStartup() {
|
|
186
182
|
const recovered = recoverTasks(dataDir);
|
|
187
183
|
let count = 0;
|
|
188
|
-
let
|
|
184
|
+
let dispatchPreserved = 0;
|
|
189
185
|
for (const persisted of recovered) {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
hint: "Legacy task file lacks origin; skipping recovery -- delete the file or wait for cleanup",
|
|
197
|
-
errorKind: "internal",
|
|
198
|
-
}, "Skipping recovered task without origin");
|
|
199
|
-
continue;
|
|
200
|
-
}
|
|
201
|
-
const task = {
|
|
202
|
-
...persisted,
|
|
203
|
-
};
|
|
186
|
+
// The persistence-write contract guarantees populated origin /
|
|
187
|
+
// notificationPolicy / dispatchState on every task file.
|
|
188
|
+
// background-task-persistence.ts rejects shape-malformed files
|
|
189
|
+
// (missing id / toolName) before they reach here; we propagate the
|
|
190
|
+
// persisted record as-is.
|
|
191
|
+
const task = persisted;
|
|
204
192
|
tasks.set(task.id, task);
|
|
205
193
|
if (persisted.status === "failed" && persisted.error === "Daemon restarted while task was running") {
|
|
194
|
+
// Recovery-without-events: if dispatchState is already "notified" or
|
|
195
|
+
// "dispatched", the dispatcher already routed pre-restart; do NOT
|
|
196
|
+
// re-emit the background_task:failed event (which would re-trigger
|
|
197
|
+
// fallback).
|
|
198
|
+
if (task.dispatchState === "notified" || task.dispatchState === "dispatched") {
|
|
199
|
+
dispatchPreserved++;
|
|
200
|
+
logger.debug({
|
|
201
|
+
taskId: task.id,
|
|
202
|
+
dispatchState: task.dispatchState,
|
|
203
|
+
hint: "Pre-restart dispatch state preserved; skipping re-emit (D-S2 recovery-without-events)",
|
|
204
|
+
}, "Recovery: skipped re-emit");
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
206
207
|
count++;
|
|
207
208
|
eventBus.emit("background_task:failed", {
|
|
208
209
|
agentId: task.origin.agentId,
|
|
@@ -218,14 +219,20 @@ export function createBackgroundTaskManager(opts) {
|
|
|
218
219
|
if (count > 0) {
|
|
219
220
|
logger.info({ count }, "Recovered background tasks marked as failed");
|
|
220
221
|
}
|
|
221
|
-
if (
|
|
222
|
-
logger.
|
|
223
|
-
skipped,
|
|
224
|
-
hint: "Legacy task files cannot be recovered without origin -- they remain on disk for audit",
|
|
225
|
-
errorKind: "internal",
|
|
226
|
-
}, "Skipped legacy task files during recovery");
|
|
222
|
+
if (dispatchPreserved > 0) {
|
|
223
|
+
logger.info({ count: dispatchPreserved }, "Recovered tasks with preserved dispatch state (no re-emit)");
|
|
227
224
|
}
|
|
228
225
|
},
|
|
226
|
+
transitionDispatchState(taskId, next) {
|
|
227
|
+
const task = tasks.get(taskId);
|
|
228
|
+
if (!task)
|
|
229
|
+
return false;
|
|
230
|
+
// Idempotent — same-state transitions are allowed (no-op write).
|
|
231
|
+
task.dispatchState = next;
|
|
232
|
+
// Persist atomically so recovery-after-SIGKILL sees the transition.
|
|
233
|
+
persistTaskSync(dataDir, task);
|
|
234
|
+
return true;
|
|
235
|
+
},
|
|
229
236
|
cleanup(maxAgeMs = 86_400_000) {
|
|
230
237
|
const cutoff = Date.now() - maxAgeMs;
|
|
231
238
|
for (const [taskId, task] of tasks) {
|
|
@@ -7,12 +7,17 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @module
|
|
9
9
|
*/
|
|
10
|
-
import { mkdirSync, writeFileSync, readFileSync, readdirSync, unlinkSync, existsSync } from "node:fs";
|
|
10
|
+
import { mkdirSync, writeFileSync, readFileSync, readdirSync, statSync, unlinkSync, existsSync } from "node:fs";
|
|
11
11
|
import { safePath } from "@comis/core";
|
|
12
12
|
/** Directory name under data dir for background task state files. */
|
|
13
13
|
export const TASK_DIR_NAME = "background-tasks";
|
|
14
14
|
/**
|
|
15
15
|
* Extract the serializable subset from a BackgroundTask.
|
|
16
|
+
*
|
|
17
|
+
* notificationPolicy + dispatchState are copied across when present so the
|
|
18
|
+
* state machine survives daemon restart-recovery. Both fields are optional in
|
|
19
|
+
* PersistedTaskState; we use spread-when-defined to avoid emitting
|
|
20
|
+
* `"notificationPolicy": undefined` to disk for callers that do not set them.
|
|
16
21
|
*/
|
|
17
22
|
function toPersistedState(task) {
|
|
18
23
|
return {
|
|
@@ -24,6 +29,8 @@ function toPersistedState(task) {
|
|
|
24
29
|
result: task.result,
|
|
25
30
|
error: task.error,
|
|
26
31
|
origin: task.origin,
|
|
32
|
+
...(task.notificationPolicy !== undefined && { notificationPolicy: task.notificationPolicy }),
|
|
33
|
+
...(task.dispatchState !== undefined && { dispatchState: task.dispatchState }),
|
|
27
34
|
};
|
|
28
35
|
}
|
|
29
36
|
/**
|
|
@@ -72,6 +79,20 @@ export function recoverTasks(dataDir) {
|
|
|
72
79
|
}
|
|
73
80
|
for (const agentId of agentDirs) {
|
|
74
81
|
const agentDir = safePath(dataDir, agentId);
|
|
82
|
+
// Guard against non-directory entries in dataDir. statSync may throw if
|
|
83
|
+
// the entry vanished between readdirSync and here; skip gracefully.
|
|
84
|
+
// Non-directory entries (lock files, READMEs, accidental
|
|
85
|
+
// file-with-agentId-name) MUST be skipped explicitly so they don't
|
|
86
|
+
// shadow legitimate agent recovery silently.
|
|
87
|
+
let dirStat;
|
|
88
|
+
try {
|
|
89
|
+
dirStat = statSync(agentDir);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (!dirStat.isDirectory())
|
|
95
|
+
continue;
|
|
75
96
|
let files;
|
|
76
97
|
try {
|
|
77
98
|
files = readdirSync(agentDir);
|
|
@@ -86,10 +107,12 @@ export function recoverTasks(dataDir) {
|
|
|
86
107
|
try {
|
|
87
108
|
const raw = readFileSync(filePath, "utf-8");
|
|
88
109
|
const parsed = JSON.parse(raw);
|
|
89
|
-
//
|
|
90
|
-
//
|
|
91
|
-
//
|
|
92
|
-
|
|
110
|
+
// Shape guard — skip completely malformed files. Tasks always carry
|
|
111
|
+
// id + toolName + origin; the producer-side persistTaskSync writes
|
|
112
|
+
// all three unconditionally. A file failing this guard is either
|
|
113
|
+
// truncated mid-write or a legacy artifact operators should clean
|
|
114
|
+
// up manually.
|
|
115
|
+
if (!parsed.id || !parsed.toolName || !parsed.origin) {
|
|
93
116
|
continue;
|
|
94
117
|
}
|
|
95
118
|
const task = parsed;
|
|
@@ -6,6 +6,38 @@
|
|
|
6
6
|
import type { BackgroundTaskOrigin } from "@comis/core";
|
|
7
7
|
export type { BackgroundTaskOrigin };
|
|
8
8
|
export type BackgroundTaskStatus = "running" | "completed" | "failed" | "cancelled";
|
|
9
|
+
/**
|
|
10
|
+
* Notification policy for a background task. Typed enum (NOT a boolean):
|
|
11
|
+
* preserves intent across restart-recovery so the recovered task's dispatch
|
|
12
|
+
* path matches its original promote-time intent. A boolean collapses to
|
|
13
|
+
* true/false on rehydrate and loses the distinction between "the operator
|
|
14
|
+
* wanted deferred routing" and "the operator wanted immediate notification".
|
|
15
|
+
*
|
|
16
|
+
* - "deferred" — Default. Wait for the dispatcher to attempt session
|
|
17
|
+
* re-entry; only fall back to user-visible notification
|
|
18
|
+
* when re-entry fails (session expired, hop cap hit).
|
|
19
|
+
* - "immediate" — Skip the dispatcher; fire user-visible notification
|
|
20
|
+
* immediately. Reserved for tasks that explicitly want
|
|
21
|
+
* the legacy literal-text notification.
|
|
22
|
+
* - "silent" — Skip both dispatcher and user-visible notification.
|
|
23
|
+
* Reserved for fully-internal tasks.
|
|
24
|
+
*
|
|
25
|
+
* Default for new promote() calls: "deferred".
|
|
26
|
+
*/
|
|
27
|
+
export type BackgroundTaskNotificationPolicy = "deferred" | "immediate" | "silent";
|
|
28
|
+
/**
|
|
29
|
+
* Three-state session lifecycle for a background task's notification routing.
|
|
30
|
+
* State-machine transitions are the single source of truth for at-most-once
|
|
31
|
+
* fallback.
|
|
32
|
+
*
|
|
33
|
+
* - "pending" — Promotion happened; no completion event yet (or completion
|
|
34
|
+
* event arrived but dispatcher has not classified it).
|
|
35
|
+
* - "notified" — Fallback notification fired (user-visible literal text);
|
|
36
|
+
* recovery-after-restart MUST NOT re-emit.
|
|
37
|
+
* - "dispatched" — Re-entry triggered against the originating session;
|
|
38
|
+
* no fallback notification needed.
|
|
39
|
+
*/
|
|
40
|
+
export type BackgroundSessionState = "pending" | "notified" | "dispatched";
|
|
9
41
|
export interface BackgroundTask {
|
|
10
42
|
id: string;
|
|
11
43
|
toolName: string;
|
|
@@ -18,6 +50,13 @@ export interface BackgroundTask {
|
|
|
18
50
|
* promote-time, persisted on disk, preserved across recoverOnStartup.
|
|
19
51
|
* Required (no silent fallback). */
|
|
20
52
|
origin: BackgroundTaskOrigin;
|
|
53
|
+
/** Live notification policy. Optional; recovery defaults to "deferred" when
|
|
54
|
+
* absent. */
|
|
55
|
+
notificationPolicy?: BackgroundTaskNotificationPolicy;
|
|
56
|
+
/** Live three-state session lifecycle. Optional; recovery defaults to
|
|
57
|
+
* "pending" when absent. The dispatcher inspects this before firing
|
|
58
|
+
* notifyFn. */
|
|
59
|
+
dispatchState?: BackgroundSessionState;
|
|
21
60
|
_promise?: Promise<unknown>;
|
|
22
61
|
_abortController?: AbortController;
|
|
23
62
|
_hardTimeoutTimer?: ReturnType<typeof setTimeout>;
|
|
@@ -34,4 +73,14 @@ export interface PersistedTaskState {
|
|
|
34
73
|
/** Persisted origin -- read back by recoverOnStartup so completion routing
|
|
35
74
|
* survives daemon restarts. */
|
|
36
75
|
origin: BackgroundTaskOrigin;
|
|
76
|
+
/**
|
|
77
|
+
* Notification policy chosen at promote time. Optional; recovery defaults
|
|
78
|
+
* to "deferred" when absent.
|
|
79
|
+
*/
|
|
80
|
+
notificationPolicy?: BackgroundTaskNotificationPolicy;
|
|
81
|
+
/**
|
|
82
|
+
* Three-state session lifecycle. Optional; recovery defaults to "pending"
|
|
83
|
+
* when absent. The dispatcher inspects this before firing notifyFn.
|
|
84
|
+
*/
|
|
85
|
+
dispatchState?: BackgroundSessionState;
|
|
37
86
|
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Completion dispatcher: routes background_task:completed/failed events
|
|
3
|
+
* through the BackgroundSessionState machine.
|
|
4
|
+
*
|
|
5
|
+
* Subscribes to background_task:completed and background_task:failed BEFORE
|
|
6
|
+
* the existing BackgroundCompletionRunner. On each event:
|
|
7
|
+
* 1. Reads `task.dispatchState`.
|
|
8
|
+
* 2. If "pending": transitions to "notified" only when the runner cannot
|
|
9
|
+
* re-enter the originating session (no active session for the formatted
|
|
10
|
+
* key, or recursion limit reached). Otherwise transitions to "dispatched"
|
|
11
|
+
* and lets the completion-runner perform re-entry.
|
|
12
|
+
* 3. If already "notified" or "dispatched": no-op (at-most-once).
|
|
13
|
+
*
|
|
14
|
+
* The runner is wired AFTER the dispatcher in setup-background-completion-
|
|
15
|
+
* runner.ts so its handler reads the updated `task.dispatchState` and skips
|
|
16
|
+
* its own work when state is "notified" (the dispatcher already fired
|
|
17
|
+
* fallback). This single-owner contract ensures the completion runner does
|
|
18
|
+
* not double-fire user-visible notifications: the dispatcher routes via
|
|
19
|
+
* persistent state instead of an in-memory event handler, and gates on
|
|
20
|
+
* state instead of unconditionally firing.
|
|
21
|
+
*
|
|
22
|
+
* **State persistence:** every transition calls `manager.transitionDispatch
|
|
23
|
+
* State(taskId, next)` (when the manager exposes it) which mutates the
|
|
24
|
+
* in-memory task AND calls persistTaskSync. Recovery-after-SIGKILL reads
|
|
25
|
+
* the persisted state and the manager skips re-emitting completion events
|
|
26
|
+
* for already-dispatched / already-notified tasks.
|
|
27
|
+
*
|
|
28
|
+
* **Failure isolation:** each handler is wrapped in suppressError so a
|
|
29
|
+
* single dispatch's failure does not tear down the subscription
|
|
30
|
+
* (AGENTS §2.1).
|
|
31
|
+
*
|
|
32
|
+
* @module
|
|
33
|
+
*/
|
|
34
|
+
import type { TypedEventBus } from "@comis/core";
|
|
35
|
+
import type { ComisLogger } from "@comis/infra";
|
|
36
|
+
import type { BackgroundTask, BackgroundSessionState, BackgroundTaskNotificationPolicy as NotificationPolicyType } from "./background-task-types.js";
|
|
37
|
+
import type { NotifyFn } from "./background-task-manager.js";
|
|
38
|
+
/**
|
|
39
|
+
* The 3-state typed enum as a runtime array. Order matches transition order:
|
|
40
|
+
* pending → (notified | dispatched).
|
|
41
|
+
*
|
|
42
|
+
* Exported as a `readonly string[]` so tests can assert
|
|
43
|
+
* `STATES === ["pending", "notified", "dispatched"]`.
|
|
44
|
+
*/
|
|
45
|
+
export declare const STATES: readonly BackgroundSessionState[];
|
|
46
|
+
/**
|
|
47
|
+
* Notification policy as a runtime object so it round-trips through
|
|
48
|
+
* JSON.parse(JSON.stringify(...)) preserving identity. A boolean would
|
|
49
|
+
* collapse to true/false on rehydrate and lose the distinction between
|
|
50
|
+
* "deferred" / "immediate" / "silent".
|
|
51
|
+
*
|
|
52
|
+
* The typed enum is the single source of truth. This runtime object is a
|
|
53
|
+
* discoverability surface (tests, debugging, logs); production code uses
|
|
54
|
+
* the type-only `BackgroundTaskNotificationPolicy` from
|
|
55
|
+
* `background-task-types.ts`.
|
|
56
|
+
*/
|
|
57
|
+
export declare const BackgroundTaskNotificationPolicy: Record<string, NotificationPolicyType>;
|
|
58
|
+
/** Public-facing handle on the dispatcher. */
|
|
59
|
+
export interface CompletionDispatcher {
|
|
60
|
+
/** Unsubscribe from the event bus. Idempotent. Awaitable so callers can
|
|
61
|
+
* ensure no in-flight handler outlives daemon shutdown. */
|
|
62
|
+
shutdown(): Promise<void>;
|
|
63
|
+
}
|
|
64
|
+
/** Minimal session-store contract the dispatcher needs (active-session check). */
|
|
65
|
+
export interface DispatcherSessionStore {
|
|
66
|
+
loadByFormattedKey(sessionKey: string): unknown | undefined;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Minimal taskManager contract: read + (optionally) persist transitions.
|
|
70
|
+
*
|
|
71
|
+
* `transitionDispatchState` is optional so the dispatcher composes cleanly
|
|
72
|
+
* with the test fixture in completion-dispatcher.test.ts (which constructs
|
|
73
|
+
* `taskManager: { getTask: vi.fn() }` and asserts the at-most-once gate
|
|
74
|
+
* without exercising state persistence). Production wiring adds
|
|
75
|
+
* `transitionDispatchState` on the real BackgroundTaskManager so the
|
|
76
|
+
* recovery-after-SIGKILL contract is binding.
|
|
77
|
+
*/
|
|
78
|
+
export interface DispatcherTaskManager {
|
|
79
|
+
getTask(taskId: string): BackgroundTask | undefined;
|
|
80
|
+
/**
|
|
81
|
+
* Atomically transition the in-memory task's dispatchState AND persist.
|
|
82
|
+
* Returns true on success; false if task does not exist. Optional —
|
|
83
|
+
* when absent, the dispatcher routes purely via in-memory state.
|
|
84
|
+
*/
|
|
85
|
+
transitionDispatchState?(taskId: string, next: BackgroundSessionState): boolean;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Dispatcher dependencies.
|
|
89
|
+
*
|
|
90
|
+
* Public minimum: `eventBus`, `taskManager`, `logger`. Tests use
|
|
91
|
+
* `notifyFn`; production wires both `notifyFn` and `fallbackNotifyFn`
|
|
92
|
+
* (they are aliases — the dispatcher prefers `fallbackNotifyFn` when
|
|
93
|
+
* both are provided so production callers reading the daemon wiring
|
|
94
|
+
* see the canonical name).
|
|
95
|
+
*
|
|
96
|
+
* `sessionStore` + `maxBackgroundHops` are optional. When absent, the
|
|
97
|
+
* dispatcher falls back to the safe behavior: pending → dispatched
|
|
98
|
+
* (let the runner attempt re-entry), no fallback notification fired
|
|
99
|
+
* from the dispatcher itself.
|
|
100
|
+
*/
|
|
101
|
+
export interface CompletionDispatcherDeps {
|
|
102
|
+
eventBus: TypedEventBus;
|
|
103
|
+
taskManager: DispatcherTaskManager;
|
|
104
|
+
/**
|
|
105
|
+
* User-visible notification fired when the dispatcher cannot route to
|
|
106
|
+
* the originating session. Either name accepted; `fallbackNotifyFn`
|
|
107
|
+
* preferred when both are provided.
|
|
108
|
+
*/
|
|
109
|
+
fallbackNotifyFn?: NotifyFn;
|
|
110
|
+
/** Alias for `fallbackNotifyFn` (test fixture compatibility). */
|
|
111
|
+
notifyFn?: NotifyFn;
|
|
112
|
+
/** Active-session check (production wiring). When absent, the dispatcher
|
|
113
|
+
* defers to the runner without firing fallback. */
|
|
114
|
+
sessionStore?: DispatcherSessionStore;
|
|
115
|
+
/** Recursion limit for background-task hop counting. When absent, the
|
|
116
|
+
* dispatcher does not enforce the cap (defers to the runner). */
|
|
117
|
+
maxBackgroundHops?: number;
|
|
118
|
+
logger: ComisLogger;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Wire the completion dispatcher against an event bus + task manager.
|
|
122
|
+
* Subscriptions are installed synchronously; call shutdown() to remove them.
|
|
123
|
+
*
|
|
124
|
+
* At-most-once fallback: the state-machine transitions on
|
|
125
|
+
* `task.dispatchState` are the single source of truth. The dispatcher's
|
|
126
|
+
* synchronous transitionDispatchState runs BEFORE the completion-runner's
|
|
127
|
+
* handler reads the updated state, by virtue of the event-bus subscribing
|
|
128
|
+
* the dispatcher first (see setup-background-completion-runner.ts).
|
|
129
|
+
*/
|
|
130
|
+
export declare function createCompletionDispatcher(deps: CompletionDispatcherDeps): CompletionDispatcher;
|