@telora/daemon 0.15.1 → 0.15.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -11
- package/build-info.json +2 -2
- package/dist/assembly-engine.d.ts +1 -1
- package/dist/assembly-engine.d.ts.map +1 -1
- package/dist/assembly-resolvers.js +41 -41
- package/dist/assembly-resolvers.js.map +1 -1
- package/dist/branch-status.d.ts +4 -4
- package/dist/branch-status.d.ts.map +1 -1
- package/dist/branch-status.js +23 -23
- package/dist/branch-status.js.map +1 -1
- package/dist/cli/connect.js +1 -1
- package/dist/cli/connect.js.map +1 -1
- package/dist/completion-detector.d.ts +1 -1
- package/dist/completion-detector.js +1 -1
- package/dist/completion-handler.d.ts +1 -1
- package/dist/completion-handler.js +4 -4
- package/dist/completion-handler.js.map +1 -1
- package/dist/condition-evaluators.js +4 -4
- package/dist/condition-evaluators.js.map +1 -1
- package/dist/control-state.d.ts +6 -6
- package/dist/control-state.d.ts.map +1 -1
- package/dist/control-state.js +43 -43
- package/dist/control-state.js.map +1 -1
- package/dist/crash-recovery-scan.d.ts +1 -1
- package/dist/crash-recovery-scan.js +20 -20
- package/dist/crash-recovery-scan.js.map +1 -1
- package/dist/crash-recovery-types.d.ts +3 -3
- package/dist/crash-recovery-types.d.ts.map +1 -1
- package/dist/crash-recovery-types.js +2 -2
- package/dist/crash-recovery-types.js.map +1 -1
- package/dist/crash-recovery.d.ts +3 -3
- package/dist/crash-recovery.d.ts.map +1 -1
- package/dist/crash-recovery.js +21 -21
- package/dist/crash-recovery.js.map +1 -1
- package/dist/daemon-process.d.ts +1 -1
- package/dist/daemon-process.d.ts.map +1 -1
- package/dist/dag-validator.d.ts +6 -6
- package/dist/dag-validator.d.ts.map +1 -1
- package/dist/dag-validator.js +2 -2
- package/dist/dag-validator.js.map +1 -1
- package/dist/delivery-guards.d.ts +1 -1
- package/dist/delivery-guards.js +1 -1
- package/dist/delivery-lifecycle.d.ts +5 -5
- package/dist/delivery-lifecycle.d.ts.map +1 -1
- package/dist/delivery-lifecycle.js +12 -12
- package/dist/delivery-lifecycle.js.map +1 -1
- package/dist/delivery-merge.js +1 -1
- package/dist/delivery-merge.js.map +1 -1
- package/dist/dependency-resolver.d.ts +7 -7
- package/dist/dependency-resolver.d.ts.map +1 -1
- package/dist/dependency-resolver.js.map +1 -1
- package/dist/directive-executor.d.ts +15 -15
- package/dist/directive-executor.d.ts.map +1 -1
- package/dist/directive-executor.js +76 -76
- package/dist/directive-executor.js.map +1 -1
- package/dist/evaluation-context.d.ts +2 -2
- package/dist/evaluation-context.d.ts.map +1 -1
- package/dist/evaluation-context.js +4 -4
- package/dist/evaluation-context.js.map +1 -1
- package/dist/focus-completion-event.d.ts +97 -0
- package/dist/focus-completion-event.d.ts.map +1 -0
- package/dist/focus-completion-event.js +257 -0
- package/dist/focus-completion-event.js.map +1 -0
- package/dist/focus-completion.d.ts +85 -0
- package/dist/focus-completion.d.ts.map +1 -0
- package/dist/focus-completion.js +459 -0
- package/dist/focus-completion.js.map +1 -0
- package/dist/focus-engine.d.ts +47 -0
- package/dist/focus-engine.d.ts.map +1 -0
- package/dist/focus-engine.js +421 -0
- package/dist/focus-engine.js.map +1 -0
- package/dist/focus-executor.d.ts +55 -0
- package/dist/focus-executor.d.ts.map +1 -0
- package/dist/focus-executor.js +549 -0
- package/dist/focus-executor.js.map +1 -0
- package/dist/focus-lifecycle.d.ts +61 -0
- package/dist/focus-lifecycle.d.ts.map +1 -0
- package/dist/focus-lifecycle.js +544 -0
- package/dist/focus-lifecycle.js.map +1 -0
- package/dist/focus-merge.d.ts +77 -0
- package/dist/focus-merge.d.ts.map +1 -0
- package/dist/focus-merge.js +378 -0
- package/dist/focus-merge.js.map +1 -0
- package/dist/focus-prompt-builder.d.ts +35 -0
- package/dist/focus-prompt-builder.d.ts.map +1 -0
- package/dist/focus-prompt-builder.js +138 -0
- package/dist/focus-prompt-builder.js.map +1 -0
- package/dist/focus-provisioning.d.ts +16 -0
- package/dist/focus-provisioning.d.ts.map +1 -0
- package/dist/focus-provisioning.js +119 -0
- package/dist/focus-provisioning.js.map +1 -0
- package/dist/focus-spawn-helpers.d.ts +67 -0
- package/dist/focus-spawn-helpers.d.ts.map +1 -0
- package/dist/focus-spawn-helpers.js +160 -0
- package/dist/focus-spawn-helpers.js.map +1 -0
- package/dist/focus-team-lifecycle.d.ts +50 -0
- package/dist/focus-team-lifecycle.d.ts.map +1 -0
- package/dist/focus-team-lifecycle.js +256 -0
- package/dist/focus-team-lifecycle.js.map +1 -0
- package/dist/focus-team-state.d.ts +24 -0
- package/dist/focus-team-state.d.ts.map +1 -0
- package/dist/focus-team-state.js +43 -0
- package/dist/focus-team-state.js.map +1 -0
- package/dist/focus-worktree-state.d.ts +47 -0
- package/dist/focus-worktree-state.d.ts.map +1 -0
- package/dist/focus-worktree-state.js +104 -0
- package/dist/focus-worktree-state.js.map +1 -0
- package/dist/git-merge.d.ts +5 -5
- package/dist/git-merge.d.ts.map +1 -1
- package/dist/git-merge.js +5 -5
- package/dist/git-merge.js.map +1 -1
- package/dist/git-state-detector.d.ts +1 -1
- package/dist/git-state-detector.js +9 -9
- package/dist/git-state-detector.js.map +1 -1
- package/dist/git-utils.d.ts +1 -1
- package/dist/git-utils.js +1 -1
- package/dist/git.d.ts +2 -2
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js +3 -3
- package/dist/git.js.map +1 -1
- package/dist/heartbeat.d.ts +4 -4
- package/dist/heartbeat.d.ts.map +1 -1
- package/dist/heartbeat.js +7 -7
- package/dist/heartbeat.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +10 -10
- package/dist/index.js.map +1 -1
- package/dist/listener-auto-advance.d.ts +2 -2
- package/dist/listener-auto-advance.js +21 -21
- package/dist/listener-auto-advance.js.map +1 -1
- package/dist/listener.d.ts +12 -12
- package/dist/listener.d.ts.map +1 -1
- package/dist/listener.js +80 -75
- package/dist/listener.js.map +1 -1
- package/dist/loop-engine.d.ts +20 -20
- package/dist/loop-engine.d.ts.map +1 -1
- package/dist/loop-engine.js +82 -82
- package/dist/loop-engine.js.map +1 -1
- package/dist/loop-event-bus.d.ts +5 -5
- package/dist/loop-event-bus.d.ts.map +1 -1
- package/dist/loop-event-bus.js +3 -3
- package/dist/loop-llm-client.d.ts +1 -1
- package/dist/loop-llm-client.js +1 -1
- package/dist/loop-variance.d.ts +1 -1
- package/dist/loop-variance.js +1 -1
- package/dist/merge-detector.d.ts +6 -6
- package/dist/merge-detector.d.ts.map +1 -1
- package/dist/merge-detector.js +47 -47
- package/dist/merge-detector.js.map +1 -1
- package/dist/otlp-log-parser.js +2 -2
- package/dist/otlp-log-parser.js.map +1 -1
- package/dist/otlp-metric-parser.js +1 -1
- package/dist/otlp-metric-parser.js.map +1 -1
- package/dist/otlp-receiver.d.ts +1 -1
- package/dist/otlp-receiver.js +7 -7
- package/dist/otlp-receiver.js.map +1 -1
- package/dist/otlp-types.d.ts +1 -1
- package/dist/otlp-types.d.ts.map +1 -1
- package/dist/otlp-types.js +3 -3
- package/dist/otlp-types.js.map +1 -1
- package/dist/output-monitor.d.ts +6 -6
- package/dist/output-monitor.d.ts.map +1 -1
- package/dist/output-monitor.js +11 -11
- package/dist/output-monitor.js.map +1 -1
- package/dist/planning-prompt-builder.d.ts +17 -15
- package/dist/planning-prompt-builder.d.ts.map +1 -1
- package/dist/planning-prompt-builder.js +34 -32
- package/dist/planning-prompt-builder.js.map +1 -1
- package/dist/pm/mitigation-correlator.d.ts +7 -7
- package/dist/pm/mitigation-correlator.d.ts.map +1 -1
- package/dist/pm/mitigation-correlator.js +33 -33
- package/dist/pm/mitigation-correlator.js.map +1 -1
- package/dist/pm-engine.js +1 -1
- package/dist/pm-engine.js.map +1 -1
- package/dist/prompt-builder.d.ts +1 -1
- package/dist/prompt-builder.js +9 -9
- package/dist/prompt-builder.js.map +1 -1
- package/dist/prompts/starter-prompt.d.ts +2 -2
- package/dist/prompts/starter-prompt.d.ts.map +1 -1
- package/dist/prompts/starter-prompt.js +6 -6
- package/dist/qa-crash-recovery.d.ts +10 -10
- package/dist/qa-crash-recovery.d.ts.map +1 -1
- package/dist/qa-crash-recovery.js +32 -32
- package/dist/qa-crash-recovery.js.map +1 -1
- package/dist/qa-dev-server.d.ts +3 -3
- package/dist/qa-dev-server.d.ts.map +1 -1
- package/dist/qa-dev-server.js +3 -3
- package/dist/qa-dev-server.js.map +1 -1
- package/dist/qa-orchestrator.d.ts +18 -18
- package/dist/qa-orchestrator.d.ts.map +1 -1
- package/dist/qa-orchestrator.js +47 -47
- package/dist/qa-orchestrator.js.map +1 -1
- package/dist/qa-provisioner.d.ts +3 -3
- package/dist/qa-provisioner.d.ts.map +1 -1
- package/dist/qa-provisioner.js +14 -14
- package/dist/qa-provisioner.js.map +1 -1
- package/dist/qa-state.d.ts +10 -10
- package/dist/qa-state.d.ts.map +1 -1
- package/dist/qa-state.js +11 -11
- package/dist/qa-state.js.map +1 -1
- package/dist/queries/control-state.d.ts +5 -5
- package/dist/queries/control-state.d.ts.map +1 -1
- package/dist/queries/control-state.js +4 -4
- package/dist/queries/control-state.js.map +1 -1
- package/dist/queries/deliveries.d.ts +28 -24
- package/dist/queries/deliveries.d.ts.map +1 -1
- package/dist/queries/deliveries.js +32 -28
- package/dist/queries/deliveries.js.map +1 -1
- package/dist/queries/focuses.d.ts +97 -0
- package/dist/queries/focuses.d.ts.map +1 -0
- package/dist/queries/focuses.js +136 -0
- package/dist/queries/focuses.js.map +1 -0
- package/dist/queries/index.d.ts +3 -3
- package/dist/queries/index.d.ts.map +1 -1
- package/dist/queries/index.js +2 -2
- package/dist/queries/index.js.map +1 -1
- package/dist/queries/qa.d.ts +16 -16
- package/dist/queries/qa.d.ts.map +1 -1
- package/dist/queries/qa.js +22 -22
- package/dist/queries/qa.js.map +1 -1
- package/dist/queries/schemas.d.ts +40 -34
- package/dist/queries/schemas.d.ts.map +1 -1
- package/dist/queries/schemas.js +31 -26
- package/dist/queries/schemas.js.map +1 -1
- package/dist/queries/sessions.d.ts +1 -1
- package/dist/queries/sessions.d.ts.map +1 -1
- package/dist/queries/sessions.js +2 -2
- package/dist/queries/sessions.js.map +1 -1
- package/dist/queries/shared.js +10 -10
- package/dist/queries/shared.js.map +1 -1
- package/dist/queries/workflows.d.ts +1 -1
- package/dist/queries/workflows.js +1 -1
- package/dist/queries/worktrees.d.ts +7 -7
- package/dist/queries/worktrees.d.ts.map +1 -1
- package/dist/queries/worktrees.js +7 -7
- package/dist/queries/worktrees.js.map +1 -1
- package/dist/review-defect-detector.d.ts +125 -0
- package/dist/review-defect-detector.d.ts.map +1 -0
- package/dist/review-defect-detector.js +289 -0
- package/dist/review-defect-detector.js.map +1 -0
- package/dist/session-lifecycle.d.ts +17 -17
- package/dist/session-lifecycle.d.ts.map +1 -1
- package/dist/session-lifecycle.js +82 -82
- package/dist/session-lifecycle.js.map +1 -1
- package/dist/spawn-cooldown.d.ts +8 -8
- package/dist/spawn-cooldown.d.ts.map +1 -1
- package/dist/spawn-cooldown.js +15 -15
- package/dist/spawn-cooldown.js.map +1 -1
- package/dist/spawn-environment.d.ts +2 -2
- package/dist/spawn-environment.d.ts.map +1 -1
- package/dist/spawn-environment.js +3 -3
- package/dist/spawn-environment.js.map +1 -1
- package/dist/spawner-lifecycle.d.ts +2 -2
- package/dist/spawner-lifecycle.d.ts.map +1 -1
- package/dist/spawner-lifecycle.js +3 -3
- package/dist/spawner-lifecycle.js.map +1 -1
- package/dist/spawner-resolution.d.ts +3 -3
- package/dist/spawner-resolution.d.ts.map +1 -1
- package/dist/spawner-resolution.js +4 -4
- package/dist/spawner-resolution.js.map +1 -1
- package/dist/spawner-stream-handlers.js +2 -2
- package/dist/spawner-stream-handlers.js.map +1 -1
- package/dist/spawner.d.ts +1 -1
- package/dist/spawner.d.ts.map +1 -1
- package/dist/spawner.js +6 -6
- package/dist/spawner.js.map +1 -1
- package/dist/stage-classifier.d.ts +1 -1
- package/dist/stage-classifier.js +1 -1
- package/dist/state-cascade.d.ts +25 -25
- package/dist/state-cascade.d.ts.map +1 -1
- package/dist/state-cascade.js +89 -89
- package/dist/state-cascade.js.map +1 -1
- package/dist/strategy-completion-event.d.ts +37 -3
- package/dist/strategy-completion-event.d.ts.map +1 -1
- package/dist/strategy-completion-event.js +78 -9
- package/dist/strategy-completion-event.js.map +1 -1
- package/dist/strategy-completion.d.ts +11 -0
- package/dist/strategy-completion.d.ts.map +1 -1
- package/dist/strategy-completion.js +22 -1
- package/dist/strategy-completion.js.map +1 -1
- package/dist/strategy-executor.d.ts.map +1 -1
- package/dist/strategy-executor.js +46 -14
- package/dist/strategy-executor.js.map +1 -1
- package/dist/strategy-merge.d.ts.map +1 -1
- package/dist/strategy-merge.js +4 -0
- package/dist/strategy-merge.js.map +1 -1
- package/dist/strategy-team-lifecycle.d.ts.map +1 -1
- package/dist/strategy-team-lifecycle.js +3 -0
- package/dist/strategy-team-lifecycle.js.map +1 -1
- package/dist/supabase.d.ts +4 -4
- package/dist/supabase.d.ts.map +1 -1
- package/dist/supabase.js +5 -5
- package/dist/supabase.js.map +1 -1
- package/dist/task-converter.d.ts +4 -4
- package/dist/task-converter.d.ts.map +1 -1
- package/dist/task-converter.js +1 -1
- package/dist/task-converter.js.map +1 -1
- package/dist/team-prompt-base.d.ts +59 -19
- package/dist/team-prompt-base.d.ts.map +1 -1
- package/dist/team-prompt-base.js +206 -25
- package/dist/team-prompt-base.js.map +1 -1
- package/dist/team-spawner.d.ts +9 -9
- package/dist/team-spawner.d.ts.map +1 -1
- package/dist/team-spawner.js +87 -83
- package/dist/team-spawner.js.map +1 -1
- package/dist/telemetry-writer.d.ts +2 -2
- package/dist/telemetry-writer.d.ts.map +1 -1
- package/dist/templates/claude-md.js +8 -8
- package/dist/templates/claude-settings.d.ts +1 -1
- package/dist/templates/claude-settings.js +2 -2
- package/dist/templates/claude-settings.js.map +1 -1
- package/dist/trigger-executor.d.ts +4 -4
- package/dist/trigger-executor.d.ts.map +1 -1
- package/dist/trigger-executor.js +11 -11
- package/dist/trigger-executor.js.map +1 -1
- package/dist/types/dag.d.ts +1 -1
- package/dist/types/delivery.d.ts +3 -3
- package/dist/types/delivery.d.ts.map +1 -1
- package/dist/types/focus.d.ts +214 -0
- package/dist/types/focus.d.ts.map +1 -0
- package/dist/types/focus.js +5 -0
- package/dist/types/focus.js.map +1 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/merge.d.ts +1 -1
- package/dist/types/session.d.ts +2 -2
- package/dist/types/session.d.ts.map +1 -1
- package/dist/types/strategy.d.ts +7 -0
- package/dist/types/strategy.d.ts.map +1 -1
- package/dist/unified-engine-lifecycle.js +11 -11
- package/dist/unified-engine-lifecycle.js.map +1 -1
- package/dist/unified-init.d.ts +1 -1
- package/dist/unified-init.js +9 -9
- package/dist/unified-init.js.map +1 -1
- package/dist/unified-shell-config.d.ts +4 -4
- package/dist/unified-shell-config.d.ts.map +1 -1
- package/dist/unified-shell-config.js +5 -5
- package/dist/unified-shell-config.js.map +1 -1
- package/dist/unified-shell-status.js +3 -3
- package/dist/unified-shell-status.js.map +1 -1
- package/dist/unified-shell.d.ts +1 -1
- package/dist/unified-shell.js +4 -4
- package/dist/unified-shell.js.map +1 -1
- package/dist/workflow-engine.d.ts +1 -1
- package/dist/workflow-engine.d.ts.map +1 -1
- package/dist/worktree-focus.d.ts +69 -0
- package/dist/worktree-focus.d.ts.map +1 -0
- package/dist/worktree-focus.js +214 -0
- package/dist/worktree-focus.js.map +1 -0
- package/dist/worktree.d.ts +10 -10
- package/dist/worktree.d.ts.map +1 -1
- package/dist/worktree.js +39 -39
- package/dist/worktree.js.map +1 -1
- package/package.json +2 -2
package/dist/state-cascade.js
CHANGED
|
@@ -2,41 +2,41 @@
|
|
|
2
2
|
* Deterministic State Cascade Engine.
|
|
3
3
|
*
|
|
4
4
|
* Implements upward state cascades from child to parent entities:
|
|
5
|
-
* - Delivery ->
|
|
5
|
+
* - Delivery -> Focus: all non-cancelled deliveries verify => focus building -> verify
|
|
6
6
|
*
|
|
7
7
|
* Note: Issue -> Delivery cascade is handled by checkDeliveryAutoAdvance
|
|
8
8
|
* in listener-auto-advance.ts.
|
|
9
9
|
*
|
|
10
10
|
* And downward reactions when parents revert:
|
|
11
|
-
* -
|
|
11
|
+
* - Focus regression: if a delivery reverts from verify, focus reverts from verify -> building
|
|
12
12
|
*
|
|
13
13
|
* Called from the daemon poll loop via runCascadeChecks().
|
|
14
14
|
*/
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
15
|
+
import { getActiveFocuses, updateDeliveryStatus as _updateDeliveryStatus, fetchEffectiveWorkflow as _fetchEffectiveWorkflow, getDeliveryIssues as _getDeliveryIssues } from './supabase.js';
|
|
16
|
+
import { getFocusDeliveries as _getFocusDeliveries, updateFocusStatus as _updateFocusStatus, fetchFocusWorkflowWithTransitions as _fetchFocusWorkflowWithTransitions } from './queries/focuses.js';
|
|
17
17
|
import { configForProduct } from './config.js';
|
|
18
18
|
import { emitLoopTrigger } from './loop-event-bus.js';
|
|
19
19
|
import { isStatusCascadable, isStatusExcludedFromCascade, isStatusTerminal } from './stage-classifier.js';
|
|
20
20
|
import { filterWorkIssues, ACTIVE_WORK_STATUSES } from './constants.js';
|
|
21
|
-
import { hasActiveTeam } from './
|
|
21
|
+
import { hasActiveTeam } from './focus-team-state.js';
|
|
22
22
|
const defaultDeps = {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
getFocusDeliveries: _getFocusDeliveries,
|
|
24
|
+
updateFocusStatus: _updateFocusStatus,
|
|
25
|
+
fetchFocusWorkflowWithTransitions: _fetchFocusWorkflowWithTransitions,
|
|
26
26
|
fetchEffectiveWorkflow: _fetchEffectiveWorkflow,
|
|
27
27
|
updateDeliveryStatus: _updateDeliveryStatus,
|
|
28
28
|
getDeliveryIssues: _getDeliveryIssues,
|
|
29
29
|
};
|
|
30
30
|
/**
|
|
31
|
-
* Check if all non-cancelled deliveries within a
|
|
32
|
-
* and if so, advance the
|
|
31
|
+
* Check if all non-cancelled deliveries within a focus have reached verify,
|
|
32
|
+
* and if so, advance the focus from building -> verify.
|
|
33
33
|
*/
|
|
34
|
-
export async function
|
|
35
|
-
// Only cascade when
|
|
36
|
-
if (
|
|
34
|
+
export async function checkDeliveryToFocusCascade(config, focusId, focusStatus, deps = defaultDeps) {
|
|
35
|
+
// Only cascade when focus is in building stage
|
|
36
|
+
if (focusStatus !== 'building')
|
|
37
37
|
return;
|
|
38
38
|
try {
|
|
39
|
-
const deliveries = await deps.
|
|
39
|
+
const deliveries = await deps.getFocusDeliveries(focusId);
|
|
40
40
|
// Filter to non-cancelled deliveries (active + completed work)
|
|
41
41
|
const activeDeliveries = deliveries.filter(d => !isStatusExcludedFromCascade(d.executionStatus ?? ''));
|
|
42
42
|
// Nothing to cascade if there are no deliveries
|
|
@@ -46,86 +46,86 @@ export async function checkDeliveryToStrategyCascade(config, strategyId, strateg
|
|
|
46
46
|
const allInVerify = activeDeliveries.every(d => isStatusCascadable(d.executionStatus ?? ''));
|
|
47
47
|
if (!allInVerify)
|
|
48
48
|
return;
|
|
49
|
-
// All deliveries are in verify/in_review/done -- advance
|
|
50
|
-
const workflow = await deps.
|
|
49
|
+
// All deliveries are in verify/in_review/done -- advance focus to verify
|
|
50
|
+
const workflow = await deps.fetchFocusWorkflowWithTransitions(focusId);
|
|
51
51
|
// Find the building and verify stages
|
|
52
52
|
const buildingStage = workflow.stages.find(s => s.name === 'building');
|
|
53
53
|
const verifyStage = workflow.stages.find(s => s.name === 'verify');
|
|
54
54
|
if (!verifyStage) {
|
|
55
|
-
console.warn('[state-cascade] No verify stage found in
|
|
55
|
+
console.warn('[state-cascade] No verify stage found in focus workflow -- cannot cascade');
|
|
56
56
|
return;
|
|
57
57
|
}
|
|
58
58
|
// Verify there's a valid building->verify transition
|
|
59
59
|
if (workflow.transitions) {
|
|
60
60
|
const transition = workflow.transitions.find(t => buildingStage && t.from_stage_id === buildingStage.id && t.to_stage_id === verifyStage.id);
|
|
61
61
|
if (!transition) {
|
|
62
|
-
console.warn('[state-cascade] No building->verify transition found in
|
|
62
|
+
console.warn('[state-cascade] No building->verify transition found in focus workflow');
|
|
63
63
|
return;
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
|
-
await deps.
|
|
67
|
-
console.log(`[state-cascade]
|
|
66
|
+
await deps.updateFocusStatus(focusId, 'verify', verifyStage.id);
|
|
67
|
+
console.log(`[state-cascade] Focus ${focusId} cascaded building -> verify: ` +
|
|
68
68
|
`all ${activeDeliveries.length} active delivery(ies) in verify or beyond`);
|
|
69
69
|
emitLoopTrigger({
|
|
70
|
-
type: '
|
|
71
|
-
|
|
70
|
+
type: 'focus_status_changed',
|
|
71
|
+
focusId,
|
|
72
72
|
detail: 'building -> verify (all deliveries complete)',
|
|
73
73
|
});
|
|
74
74
|
}
|
|
75
75
|
catch (err) {
|
|
76
|
-
console.warn(`[state-cascade] Failed to check delivery->
|
|
76
|
+
console.warn(`[state-cascade] Failed to check delivery->focus cascade for ${focusId}:`, err.message);
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
/**
|
|
80
|
-
* If a
|
|
81
|
-
* non-complete status, regress the
|
|
80
|
+
* If a focus is in verify/in_review but a delivery has reverted to a
|
|
81
|
+
* non-complete status, regress the focus back to building.
|
|
82
82
|
*/
|
|
83
|
-
export async function
|
|
84
|
-
// Only regress if
|
|
85
|
-
// Terminal
|
|
86
|
-
if (!isStatusCascadable(
|
|
83
|
+
export async function handleFocusRegression(config, focusId, focusStatus, deps = defaultDeps) {
|
|
84
|
+
// Only regress if focus is in a cascadable but non-terminal stage (verify, in_review).
|
|
85
|
+
// Terminal focuses (done, cancelled) should not regress.
|
|
86
|
+
if (!isStatusCascadable(focusStatus) || isStatusTerminal(focusStatus))
|
|
87
87
|
return;
|
|
88
88
|
try {
|
|
89
|
-
const deliveries = await deps.
|
|
89
|
+
const deliveries = await deps.getFocusDeliveries(focusId);
|
|
90
90
|
// Check if any non-cancelled delivery is NOT in a complete status
|
|
91
91
|
const activeDeliveries = deliveries.filter(d => !isStatusExcludedFromCascade(d.executionStatus ?? ''));
|
|
92
92
|
const hasIncomplete = activeDeliveries.some(d => !isStatusCascadable(d.executionStatus ?? ''));
|
|
93
93
|
if (!hasIncomplete)
|
|
94
94
|
return;
|
|
95
|
-
// A delivery has reverted -- regress
|
|
96
|
-
const workflow = await deps.
|
|
95
|
+
// A delivery has reverted -- regress focus back to building
|
|
96
|
+
const workflow = await deps.fetchFocusWorkflowWithTransitions(focusId);
|
|
97
97
|
const buildingStage = workflow.stages.find(s => s.name === 'building');
|
|
98
98
|
if (!buildingStage) {
|
|
99
|
-
console.warn('[state-cascade] No building stage found in
|
|
99
|
+
console.warn('[state-cascade] No building stage found in focus workflow -- cannot regress');
|
|
100
100
|
return;
|
|
101
101
|
}
|
|
102
|
-
await deps.
|
|
103
|
-
console.log(`[state-cascade]
|
|
102
|
+
await deps.updateFocusStatus(focusId, 'building', buildingStage.id, { reviewRequestedAt: null });
|
|
103
|
+
console.log(`[state-cascade] Focus ${focusId} regressed ${focusStatus} -> building: ` +
|
|
104
104
|
`delivery reverted to non-verify status (review_requested_at cleared)`);
|
|
105
105
|
emitLoopTrigger({
|
|
106
106
|
type: 'review_completed',
|
|
107
|
-
|
|
108
|
-
detail: `${
|
|
107
|
+
focusId,
|
|
108
|
+
detail: `${focusStatus} -> building (delivery regression, review cleared)`,
|
|
109
109
|
});
|
|
110
110
|
}
|
|
111
111
|
catch (err) {
|
|
112
|
-
console.warn(`[state-cascade] Failed to check
|
|
112
|
+
console.warn(`[state-cascade] Failed to check focus regression for ${focusId}:`, err.message);
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
/**
|
|
116
|
-
* When a
|
|
116
|
+
* When a focus reaches verify and has pipeline_config.review.enabled,
|
|
117
117
|
* automatically trigger AI review by setting review_requested_at,
|
|
118
|
-
* transitioning the
|
|
118
|
+
* transitioning the focus to in_review, and cascading deliveries
|
|
119
119
|
* from verify to in_review.
|
|
120
120
|
*/
|
|
121
|
-
export async function checkAutoReview(config,
|
|
122
|
-
// Only trigger when
|
|
123
|
-
if (
|
|
121
|
+
export async function checkAutoReview(config, focusId, focusStatus, pipelineConfig, deps = defaultDeps) {
|
|
122
|
+
// Only trigger when focus just reached verify and review is enabled
|
|
123
|
+
if (focusStatus !== 'verify')
|
|
124
124
|
return;
|
|
125
125
|
if (!pipelineConfig?.review?.enabled)
|
|
126
126
|
return;
|
|
127
127
|
try {
|
|
128
|
-
const deliveries = await deps.
|
|
128
|
+
const deliveries = await deps.getFocusDeliveries(focusId);
|
|
129
129
|
const activeDeliveries = deliveries.filter(d => !isStatusExcludedFromCascade(d.executionStatus ?? ''));
|
|
130
130
|
// Only auto-review when ALL non-cancelled deliveries are in verify or done
|
|
131
131
|
const allComplete = activeDeliveries.every(d => isStatusCascadable(d.executionStatus ?? ''));
|
|
@@ -138,36 +138,36 @@ export async function checkAutoReview(config, strategyId, strategyStatus, pipeli
|
|
|
138
138
|
const allDone = activeDeliveries.every(d => d.executionStatus === 'done');
|
|
139
139
|
if (allDone)
|
|
140
140
|
return;
|
|
141
|
-
// Transition
|
|
142
|
-
const
|
|
143
|
-
const inReviewStage =
|
|
141
|
+
// Transition focus to in_review and set review_requested_at
|
|
142
|
+
const focusWorkflow = await deps.fetchFocusWorkflowWithTransitions(focusId);
|
|
143
|
+
const inReviewStage = focusWorkflow.stages.find(s => s.name === 'in_review');
|
|
144
144
|
if (!inReviewStage) {
|
|
145
|
-
console.warn('[state-cascade] Auto-review: no in_review stage in
|
|
145
|
+
console.warn('[state-cascade] Auto-review: no in_review stage in focus workflow');
|
|
146
146
|
return;
|
|
147
147
|
}
|
|
148
|
-
await deps.
|
|
148
|
+
await deps.updateFocusStatus(focusId, 'in_review', inReviewStage.id, { reviewRequestedAt: new Date().toISOString() });
|
|
149
149
|
// Delivery cascade to in_review is handled by cascadeDeliveriesToInReview
|
|
150
150
|
// in the main poll loop (covers both auto and manual review triggers).
|
|
151
|
-
console.log(`[state-cascade] Auto-review triggered for
|
|
152
|
-
`
|
|
151
|
+
console.log(`[state-cascade] Auto-review triggered for focus ${focusId}: ` +
|
|
152
|
+
`focus transitioned to in_review`);
|
|
153
153
|
emitLoopTrigger({
|
|
154
|
-
type: '
|
|
155
|
-
|
|
154
|
+
type: 'focus_status_changed',
|
|
155
|
+
focusId,
|
|
156
156
|
detail: 'verify -> in_review (auto-review triggered)',
|
|
157
157
|
});
|
|
158
158
|
}
|
|
159
159
|
catch (err) {
|
|
160
|
-
console.warn(`[state-cascade] Failed to check auto-review for ${
|
|
160
|
+
console.warn(`[state-cascade] Failed to check auto-review for ${focusId}:`, err.message);
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
163
|
/**
|
|
164
|
-
* When a
|
|
164
|
+
* When a focus is in_review, ensure its verify deliveries are moved to in_review.
|
|
165
165
|
* This handles both auto-review (where checkAutoReview does it inline) and manual
|
|
166
|
-
* review (where the UI sets the
|
|
166
|
+
* review (where the UI sets the focus to in_review but doesn't touch deliveries).
|
|
167
167
|
*/
|
|
168
|
-
async function cascadeDeliveriesToInReview(
|
|
168
|
+
async function cascadeDeliveriesToInReview(focusId, deps = defaultDeps) {
|
|
169
169
|
try {
|
|
170
|
-
const deliveries = await deps.
|
|
170
|
+
const deliveries = await deps.getFocusDeliveries(focusId);
|
|
171
171
|
for (const d of deliveries) {
|
|
172
172
|
if (d.executionStatus === 'verify') {
|
|
173
173
|
try {
|
|
@@ -183,26 +183,26 @@ async function cascadeDeliveriesToInReview(strategyId, deps = defaultDeps) {
|
|
|
183
183
|
}
|
|
184
184
|
}
|
|
185
185
|
catch (err) {
|
|
186
|
-
console.warn(`[state-cascade] Failed to cascade deliveries to in_review for ${
|
|
186
|
+
console.warn(`[state-cascade] Failed to cascade deliveries to in_review for ${focusId}: ${err.message}`);
|
|
187
187
|
}
|
|
188
188
|
}
|
|
189
189
|
/**
|
|
190
|
-
* When a
|
|
190
|
+
* When a focus is in_review but no review team is running, check whether
|
|
191
191
|
* all in_review deliveries have passed (no open work issues). If so, route
|
|
192
|
-
* them to done and move the
|
|
192
|
+
* them to done and move the focus back to verify.
|
|
193
193
|
*
|
|
194
194
|
* This handles the case where auto-review triggers but no review team spawns
|
|
195
195
|
* (e.g., no agent_directive on the in_review stage, or no active team to
|
|
196
|
-
* receive an inject directive). Without this, the
|
|
196
|
+
* receive an inject directive). Without this, the focus is stuck in
|
|
197
197
|
* in_review forever.
|
|
198
198
|
*/
|
|
199
|
-
export async function checkReviewCompletion(
|
|
199
|
+
export async function checkReviewCompletion(focusId, deps = defaultDeps) {
|
|
200
200
|
// Only act when no team is running -- if a team is active, let the
|
|
201
201
|
// review exit handler in handleTeamCompletion deal with it.
|
|
202
|
-
if (hasActiveTeam(
|
|
202
|
+
if (hasActiveTeam(focusId))
|
|
203
203
|
return;
|
|
204
204
|
try {
|
|
205
|
-
const deliveries = await deps.
|
|
205
|
+
const deliveries = await deps.getFocusDeliveries(focusId);
|
|
206
206
|
const inReviewDeliveries = deliveries.filter(d => d.executionStatus === 'in_review');
|
|
207
207
|
if (inReviewDeliveries.length === 0)
|
|
208
208
|
return;
|
|
@@ -231,52 +231,52 @@ export async function checkReviewCompletion(strategyId, deps = defaultDeps) {
|
|
|
231
231
|
console.warn(`[state-cascade] Failed to move delivery "${d.name}" to done: ${err.message}`);
|
|
232
232
|
}
|
|
233
233
|
}
|
|
234
|
-
// Move
|
|
235
|
-
const workflow = await deps.
|
|
234
|
+
// Move focus back to verify
|
|
235
|
+
const workflow = await deps.fetchFocusWorkflowWithTransitions(focusId);
|
|
236
236
|
const verifyStage = workflow.stages.find(s => s.name === 'verify');
|
|
237
237
|
if (verifyStage) {
|
|
238
|
-
await deps.
|
|
239
|
-
console.log(`[state-cascade] Review complete (no team):
|
|
238
|
+
await deps.updateFocusStatus(focusId, 'verify', verifyStage.id, { reviewRequestedAt: null });
|
|
239
|
+
console.log(`[state-cascade] Review complete (no team): focus moved to verify`);
|
|
240
240
|
emitLoopTrigger({
|
|
241
241
|
type: 'review_completed',
|
|
242
|
-
|
|
242
|
+
focusId,
|
|
243
243
|
detail: 'in_review -> verify (auto-completed by cascade, no review team)',
|
|
244
244
|
});
|
|
245
245
|
}
|
|
246
246
|
}
|
|
247
247
|
catch (err) {
|
|
248
|
-
console.warn(`[state-cascade] Failed to check review completion for ${
|
|
248
|
+
console.warn(`[state-cascade] Failed to check review completion for ${focusId}: ${err.message}`);
|
|
249
249
|
}
|
|
250
250
|
}
|
|
251
251
|
/**
|
|
252
|
-
* Run all cascade checks for active
|
|
252
|
+
* Run all cascade checks for active focuses across all configured products.
|
|
253
253
|
*
|
|
254
|
-
* Called from the daemon poll loop. For each active
|
|
255
|
-
* 1. Check delivery->
|
|
256
|
-
* 2. Check auto-review (
|
|
257
|
-
* 3. Complete stuck reviews (
|
|
258
|
-
* 4. Check for
|
|
254
|
+
* Called from the daemon poll loop. For each active focus:
|
|
255
|
+
* 1. Check delivery->focus cascade (all deliveries verify => focus verify)
|
|
256
|
+
* 2. Check auto-review (focus in verify + review.enabled)
|
|
257
|
+
* 3. Complete stuck reviews (focus in_review + no team running + all pass)
|
|
258
|
+
* 4. Check for focus regression (delivery reverted => focus back to building)
|
|
259
259
|
*/
|
|
260
260
|
export async function runCascadeChecks(config) {
|
|
261
261
|
for (const product of config.products) {
|
|
262
262
|
const pc = configForProduct(config, product);
|
|
263
263
|
try {
|
|
264
|
-
const
|
|
265
|
-
for (const
|
|
266
|
-
// Check delivery ->
|
|
267
|
-
await
|
|
268
|
-
// Check auto-review (
|
|
269
|
-
await checkAutoReview(pc,
|
|
270
|
-
// Cascade deliveries to in_review when
|
|
264
|
+
const focuses = await getActiveFocuses(pc.organizationId, product.id);
|
|
265
|
+
for (const focus of focuses) {
|
|
266
|
+
// Check delivery -> focus cascade
|
|
267
|
+
await checkDeliveryToFocusCascade(pc, focus.focus_id, focus.status);
|
|
268
|
+
// Check auto-review (focus in verify + review.enabled)
|
|
269
|
+
await checkAutoReview(pc, focus.focus_id, focus.status, focus.pipeline_config);
|
|
270
|
+
// Cascade deliveries to in_review when focus is in_review
|
|
271
271
|
// (covers both auto-review and manual review button)
|
|
272
|
-
if (
|
|
273
|
-
await cascadeDeliveriesToInReview(
|
|
272
|
+
if (focus.status === 'in_review') {
|
|
273
|
+
await cascadeDeliveriesToInReview(focus.focus_id);
|
|
274
274
|
// Complete stuck reviews: if no team is running and all
|
|
275
275
|
// in_review deliveries pass, route to done and move to verify
|
|
276
|
-
await checkReviewCompletion(
|
|
276
|
+
await checkReviewCompletion(focus.focus_id);
|
|
277
277
|
}
|
|
278
|
-
// Check for
|
|
279
|
-
await
|
|
278
|
+
// Check for focus regression
|
|
279
|
+
await handleFocusRegression(pc, focus.focus_id, focus.status);
|
|
280
280
|
}
|
|
281
281
|
}
|
|
282
282
|
catch (err) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state-cascade.js","sourceRoot":"","sources":["../src/state-cascade.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"state-cascade.js","sourceRoot":"","sources":["../src/state-cascade.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
* Strategy completion event handler - reacts to CompletionDetector events.
|
|
3
3
|
*
|
|
4
4
|
* Extracted from strategy-executor.ts. Handles the decision logic when a
|
|
5
|
-
* team lead completes a work cycle: terminate if done,
|
|
5
|
+
* team lead completes a work cycle: terminate if done, send more work, or
|
|
6
|
+
* (for planning teams) refresh from MCP-written deliveries / escalate.
|
|
6
7
|
*/
|
|
7
8
|
import type { ChildProcess } from 'node:child_process';
|
|
8
|
-
import type { StrategyTeamState } from './types.js';
|
|
9
|
+
import type { StrategyTeamState, StrategyDeliveryInfo, StrategyIssueInfo } from './types.js';
|
|
9
10
|
import { CompletionDetector, type CompletionInfo } from './completion-detector.js';
|
|
11
|
+
/** Reason string emitted when a planning team produces no deliveries. */
|
|
12
|
+
export declare const PLANNING_NO_DELIVERIES_REASON = "planning produced no deliveries";
|
|
10
13
|
export interface CompletionEventContext {
|
|
11
14
|
strategyId: string;
|
|
12
15
|
strategyName: string;
|
|
@@ -15,6 +18,37 @@ export interface CompletionEventContext {
|
|
|
15
18
|
proc: ChildProcess;
|
|
16
19
|
completionInfo: CompletionInfo;
|
|
17
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Injectable dependencies. Defaults to the real implementations; tests can
|
|
23
|
+
* override them to assert behavior without spinning up Supabase/MCP.
|
|
24
|
+
*/
|
|
25
|
+
export interface CompletionEventDeps {
|
|
26
|
+
getStrategyDeliveries: (strategyId: string) => Promise<StrategyDeliveryInfo[]>;
|
|
27
|
+
getStrategyIssues: (strategyId: string) => Promise<StrategyIssueInfo[]>;
|
|
28
|
+
createEscalation: (params: {
|
|
29
|
+
organizationId: string;
|
|
30
|
+
sessionId: string;
|
|
31
|
+
issueId: string | null;
|
|
32
|
+
reasonType: string;
|
|
33
|
+
description: string;
|
|
34
|
+
whatWasTried?: string;
|
|
35
|
+
helpNeeded?: string;
|
|
36
|
+
}) => Promise<void>;
|
|
37
|
+
terminateTeam: (strategyId: string) => boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Escalate when a planning team finishes its initial turn without writing
|
|
41
|
+
* any deliveries via MCP. The team is then terminated -- no respawn.
|
|
42
|
+
*
|
|
43
|
+
* Exported so tests and sister deliveries can verify the contract.
|
|
44
|
+
*/
|
|
45
|
+
export declare function escalatePlanningFailure(params: {
|
|
46
|
+
organizationId: string;
|
|
47
|
+
sessionId: string;
|
|
48
|
+
strategyId: string;
|
|
49
|
+
strategyName: string;
|
|
50
|
+
agentRoleId: string;
|
|
51
|
+
}, deps?: Pick<CompletionEventDeps, 'createEscalation'>): Promise<void>;
|
|
18
52
|
/**
|
|
19
53
|
* Handle a 'complete' event from the CompletionDetector.
|
|
20
54
|
*
|
|
@@ -25,5 +59,5 @@ export interface CompletionEventContext {
|
|
|
25
59
|
* Extracted from the inline event callback in spawnStrategyTeam to eliminate
|
|
26
60
|
* deep nesting inside an async Promise chain inside an event listener.
|
|
27
61
|
*/
|
|
28
|
-
export declare function handleCompletionEvent(ctx: CompletionEventContext): Promise<void>;
|
|
62
|
+
export declare function handleCompletionEvent(ctx: CompletionEventContext, deps?: CompletionEventDeps): Promise<void>;
|
|
29
63
|
//# sourceMappingURL=strategy-completion-event.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"strategy-completion-event.d.ts","sourceRoot":"","sources":["../src/strategy-completion-event.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"strategy-completion-event.d.ts","sourceRoot":"","sources":["../src/strategy-completion-event.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE7F,OAAO,EAAE,kBAAkB,EAAE,KAAK,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAQnF,yEAAyE;AACzE,eAAO,MAAM,6BAA6B,oCAAoC,CAAC;AAI/E,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,iBAAiB,CAAC;IAC7B,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,IAAI,EAAE,YAAY,CAAC;IACnB,cAAc,EAAE,cAAc,CAAC;CAChC;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,qBAAqB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAC;IAC/E,iBAAiB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACxE,gBAAgB,EAAE,CAAC,MAAM,EAAE;QACzB,cAAc,EAAE,MAAM,CAAC;QACvB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpB,aAAa,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC;CAChD;AASD;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE;IACN,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB,EACD,IAAI,GAAE,IAAI,CAAC,mBAAmB,EAAE,kBAAkB,CAAe,GAChE,OAAO,CAAC,IAAI,CAAC,CA+Bf;AAID;;;;;;;;;GASG;AACH,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,sBAAsB,EAC3B,IAAI,GAAE,mBAAiC,GACtC,OAAO,CAAC,IAAI,CAAC,CAoGf"}
|
|
@@ -2,14 +2,55 @@
|
|
|
2
2
|
* Strategy completion event handler - reacts to CompletionDetector events.
|
|
3
3
|
*
|
|
4
4
|
* Extracted from strategy-executor.ts. Handles the decision logic when a
|
|
5
|
-
* team lead completes a work cycle: terminate if done,
|
|
5
|
+
* team lead completes a work cycle: terminate if done, send more work, or
|
|
6
|
+
* (for planning teams) refresh from MCP-written deliveries / escalate.
|
|
6
7
|
*/
|
|
7
|
-
import { sendMessage } from '@telora/daemon-core';
|
|
8
|
+
import { sendMessage, withRetry, ESCALATION_REASONS } from '@telora/daemon-core';
|
|
8
9
|
import { isStatusTerminal, isStatusAgentActionable } from './stage-classifier.js';
|
|
9
10
|
import { getStrategyDeliveries, getStrategyIssues } from './queries/strategies.js';
|
|
10
11
|
import { buildWakeMessage } from './strategy-prompt-builder.js';
|
|
11
12
|
import { OPEN_ISSUE_STATUSES } from './constants.js';
|
|
12
|
-
import { terminateTeam } from './strategy-team-lifecycle.js';
|
|
13
|
+
import { terminateTeam as defaultTerminateTeam } from './strategy-team-lifecycle.js';
|
|
14
|
+
import { createEscalation as defaultCreateEscalation } from './queries/issues.js';
|
|
15
|
+
/** Reason string emitted when a planning team produces no deliveries. */
|
|
16
|
+
export const PLANNING_NO_DELIVERIES_REASON = 'planning produced no deliveries';
|
|
17
|
+
const defaultDeps = {
|
|
18
|
+
getStrategyDeliveries,
|
|
19
|
+
getStrategyIssues,
|
|
20
|
+
createEscalation: defaultCreateEscalation,
|
|
21
|
+
terminateTeam: defaultTerminateTeam,
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Escalate when a planning team finishes its initial turn without writing
|
|
25
|
+
* any deliveries via MCP. The team is then terminated -- no respawn.
|
|
26
|
+
*
|
|
27
|
+
* Exported so tests and sister deliveries can verify the contract.
|
|
28
|
+
*/
|
|
29
|
+
export async function escalatePlanningFailure(params, deps = defaultDeps) {
|
|
30
|
+
const { sessionId, strategyName, agentRoleId } = params;
|
|
31
|
+
try {
|
|
32
|
+
await withRetry(() => deps.createEscalation({
|
|
33
|
+
organizationId: params.organizationId,
|
|
34
|
+
sessionId,
|
|
35
|
+
issueId: null,
|
|
36
|
+
reasonType: ESCALATION_REASONS.NEEDS_CLARIFICATION,
|
|
37
|
+
description: `Planning team for strategy "${strategyName}" finished its initial turn without ` +
|
|
38
|
+
`creating any deliveries. Reason: ${PLANNING_NO_DELIVERIES_REASON}.\n\n` +
|
|
39
|
+
`**Strategy:** ${strategyName}\n` +
|
|
40
|
+
`**Strategy ID:** ${params.strategyId}\n` +
|
|
41
|
+
`**Agent role:** ${agentRoleId}\n\n` +
|
|
42
|
+
`The team has been terminated. A human must either scope the strategy ` +
|
|
43
|
+
`manually or re-queue it after clarifying intent.`,
|
|
44
|
+
whatWasTried: `Spawned a planning team to scope deliveries for "${strategyName}".`,
|
|
45
|
+
helpNeeded: `Review the strategy intent and either scope deliveries manually or update the strategy description so the next planning attempt can succeed.`,
|
|
46
|
+
}), { maxAttempts: 3, label: `escalation-planning-no-deliveries-${params.strategyId}` });
|
|
47
|
+
console.log(`[strategy-executor] Created planning-failure escalation for "${strategyName}" ` +
|
|
48
|
+
`(reason: ${PLANNING_NO_DELIVERIES_REASON})`);
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
console.error(`[strategy-executor] Failed to create planning-failure escalation for "${strategyName}": ${err.message}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
13
54
|
// ── Handler ─────────────────────────────────────────────────────────────
|
|
14
55
|
/**
|
|
15
56
|
* Handle a 'complete' event from the CompletionDetector.
|
|
@@ -21,18 +62,46 @@ import { terminateTeam } from './strategy-team-lifecycle.js';
|
|
|
21
62
|
* Extracted from the inline event callback in spawnStrategyTeam to eliminate
|
|
22
63
|
* deep nesting inside an async Promise chain inside an event listener.
|
|
23
64
|
*/
|
|
24
|
-
export async function handleCompletionEvent(ctx) {
|
|
65
|
+
export async function handleCompletionEvent(ctx, deps = defaultDeps) {
|
|
25
66
|
const { strategyId, strategyName, teamState, completionDetector, proc } = ctx;
|
|
26
67
|
const [currentDeliveries, currentIssues] = await Promise.all([
|
|
27
|
-
getStrategyDeliveries(strategyId),
|
|
28
|
-
getStrategyIssues(strategyId),
|
|
68
|
+
deps.getStrategyDeliveries(strategyId),
|
|
69
|
+
deps.getStrategyIssues(strategyId),
|
|
29
70
|
]);
|
|
71
|
+
// Wake-cycle refresh (Option A): planning teams spawn with knownDeliveryIds
|
|
72
|
+
// empty. The MCP-driven planning turn writes deliveries to the DB, so we
|
|
73
|
+
// re-snapshot them here before any downstream merge/completion logic looks
|
|
74
|
+
// at the set. WHY Option A: keeps the refresh on the existing wake path
|
|
75
|
+
// instead of polling, so it runs exactly when new deliveries become visible.
|
|
76
|
+
if (teamState.planningPhase) {
|
|
77
|
+
if (currentDeliveries.length === 0) {
|
|
78
|
+
console.warn(`[strategy-executor] Planning team for "${strategyName}" produced no deliveries ` +
|
|
79
|
+
`-- escalating and terminating`);
|
|
80
|
+
await escalatePlanningFailure({
|
|
81
|
+
organizationId: teamState.organizationId,
|
|
82
|
+
sessionId: teamState.leadSessionId ?? '',
|
|
83
|
+
strategyId,
|
|
84
|
+
strategyName,
|
|
85
|
+
agentRoleId: teamState.roleId,
|
|
86
|
+
}, deps);
|
|
87
|
+
teamState.shutdownReason = 'work_complete';
|
|
88
|
+
deps.terminateTeam(strategyId);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
for (const d of currentDeliveries) {
|
|
92
|
+
teamState.knownDeliveryIds.add(d.id);
|
|
93
|
+
teamState.deliveryStageIds.set(d.id, d.currentWorkflowStageId);
|
|
94
|
+
}
|
|
95
|
+
teamState.planningPhase = false;
|
|
96
|
+
console.log(`[strategy-executor] Planning refresh for "${strategyName}": ` +
|
|
97
|
+
`${currentDeliveries.length} delivery(ies) discovered`);
|
|
98
|
+
}
|
|
30
99
|
// If all deliveries are terminal, shut down.
|
|
31
100
|
const allTerminal = currentDeliveries.every(d => isStatusTerminal(d.executionStatus ?? ''));
|
|
32
101
|
if (allTerminal) {
|
|
33
102
|
console.log(`[strategy-executor] All deliveries terminal for "${strategyName}" -- terminating team`);
|
|
34
103
|
teamState.shutdownReason = 'work_complete';
|
|
35
|
-
terminateTeam(strategyId);
|
|
104
|
+
deps.terminateTeam(strategyId);
|
|
36
105
|
return;
|
|
37
106
|
}
|
|
38
107
|
// Check if there are actionable deliveries with open issues.
|
|
@@ -42,7 +111,7 @@ export async function handleCompletionEvent(ctx) {
|
|
|
42
111
|
if (actionableDeliveryIds.size === 0) {
|
|
43
112
|
console.log(`[strategy-executor] No actionable deliveries for "${strategyName}" -- terminating team`);
|
|
44
113
|
teamState.shutdownReason = 'work_complete';
|
|
45
|
-
terminateTeam(strategyId);
|
|
114
|
+
deps.terminateTeam(strategyId);
|
|
46
115
|
return;
|
|
47
116
|
}
|
|
48
117
|
// Check for open issues across actionable deliveries.
|
|
@@ -51,7 +120,7 @@ export async function handleCompletionEvent(ctx) {
|
|
|
51
120
|
console.log(`[strategy-executor] Actionable deliveries have no open issues for "${strategyName}" -- ` +
|
|
52
121
|
`terminating team. Auto-advance will handle verify transition.`);
|
|
53
122
|
teamState.shutdownReason = 'work_complete';
|
|
54
|
-
terminateTeam(strategyId);
|
|
123
|
+
deps.terminateTeam(strategyId);
|
|
55
124
|
return;
|
|
56
125
|
}
|
|
57
126
|
// Mid-strategy handoff: actionable work with open issues remains.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"strategy-completion-event.js","sourceRoot":"","sources":["../src/strategy-completion-event.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"strategy-completion-event.js","sourceRoot":"","sources":["../src/strategy-completion-event.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,6 +8,17 @@
|
|
|
8
8
|
import type { DaemonConfig, StrategyTeamState, StrategyDeliveryInfo, Workflow, PolicyFailureMode } from './types.js';
|
|
9
9
|
import type { StageAdvanceResult } from './delivery-lifecycle.js';
|
|
10
10
|
export { isStatusTerminal, isStatusAgentActionable } from './stage-classifier.js';
|
|
11
|
+
/**
|
|
12
|
+
* Decide whether to attempt mergeStrategyBranch on team exit.
|
|
13
|
+
*
|
|
14
|
+
* Skip merge when:
|
|
15
|
+
* - The team did not succeed (failed exit or unclean shutdown), OR
|
|
16
|
+
* - The team is still in its planning phase (no deliveries scoped, nothing
|
|
17
|
+
* to merge -- this covers cancellation mid-planning).
|
|
18
|
+
*
|
|
19
|
+
* Exported for unit testing the gate logic in isolation.
|
|
20
|
+
*/
|
|
21
|
+
export declare function shouldAttemptMerge(succeeded: boolean, teamState: Pick<StrategyTeamState, 'planningPhase'>): boolean;
|
|
11
22
|
export interface TeamCompletionParams {
|
|
12
23
|
config: DaemonConfig;
|
|
13
24
|
teamState: StrategyTeamState;
|