@telora/daemon 0.17.36 → 0.17.42
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/build-info.json +5 -3
- package/dist/assembly-engine.d.ts +6 -0
- package/dist/assembly-engine.d.ts.map +1 -1
- package/dist/assembly-engine.js +19 -0
- package/dist/assembly-engine.js.map +1 -1
- package/dist/assembly-resolvers.d.ts +17 -8
- package/dist/assembly-resolvers.d.ts.map +1 -1
- package/dist/assembly-resolvers.js +19 -8
- package/dist/assembly-resolvers.js.map +1 -1
- package/dist/cli/session-state.d.ts +10 -0
- package/dist/cli/session-state.d.ts.map +1 -1
- package/dist/cli/session-state.js +31 -0
- package/dist/cli/session-state.js.map +1 -1
- package/dist/completion/completion-decision.d.ts +83 -0
- package/dist/completion/completion-decision.d.ts.map +1 -0
- package/dist/completion/completion-decision.js +48 -0
- package/dist/completion/completion-decision.js.map +1 -0
- package/dist/completion/event-escalations.d.ts +97 -0
- package/dist/completion/event-escalations.d.ts.map +1 -0
- package/dist/completion/event-escalations.js +213 -0
- package/dist/completion/event-escalations.js.map +1 -0
- package/dist/completion/event.d.ts +1 -72
- package/dist/completion/event.d.ts.map +1 -1
- package/dist/completion/event.js +148 -322
- package/dist/completion/event.js.map +1 -1
- package/dist/completion/exit-classification.d.ts +82 -0
- package/dist/completion/exit-classification.d.ts.map +1 -0
- package/dist/completion/exit-classification.js +61 -0
- package/dist/completion/exit-classification.js.map +1 -0
- package/dist/completion/index.d.ts +14 -5
- package/dist/completion/index.d.ts.map +1 -1
- package/dist/completion/index.js +14 -5
- package/dist/completion/index.js.map +1 -1
- package/dist/completion/merge-phase.d.ts +114 -0
- package/dist/completion/merge-phase.d.ts.map +1 -0
- package/dist/completion/merge-phase.js +198 -0
- package/dist/completion/merge-phase.js.map +1 -0
- package/dist/completion/review-exit-phase.d.ts +82 -0
- package/dist/completion/review-exit-phase.d.ts.map +1 -0
- package/dist/completion/review-exit-phase.js +228 -0
- package/dist/completion/review-exit-phase.js.map +1 -0
- package/dist/completion/status-advance-phase.d.ts +61 -0
- package/dist/completion/status-advance-phase.d.ts.map +1 -0
- package/dist/completion/status-advance-phase.js +182 -0
- package/dist/completion/status-advance-phase.js.map +1 -0
- package/dist/completion/team-completion.d.ts +28 -269
- package/dist/completion/team-completion.d.ts.map +1 -1
- package/dist/completion/team-completion.js +145 -676
- package/dist/completion/team-completion.js.map +1 -1
- package/dist/daemon-process.d.ts +18 -2
- package/dist/daemon-process.d.ts.map +1 -1
- package/dist/daemon-process.js +7 -2
- package/dist/daemon-process.js.map +1 -1
- package/dist/directive/close-loop-stage.d.ts +50 -0
- package/dist/directive/close-loop-stage.d.ts.map +1 -0
- package/dist/directive/close-loop-stage.js +196 -0
- package/dist/directive/close-loop-stage.js.map +1 -0
- package/dist/directive/directive-assembly.d.ts +33 -0
- package/dist/directive/directive-assembly.d.ts.map +1 -0
- package/dist/directive/directive-assembly.js +77 -0
- package/dist/directive/directive-assembly.js.map +1 -0
- package/dist/directive/directive-dispatch.d.ts +103 -0
- package/dist/directive/directive-dispatch.d.ts.map +1 -0
- package/dist/directive/directive-dispatch.js +279 -0
- package/dist/directive/directive-dispatch.js.map +1 -0
- package/dist/directive/phase-sync.d.ts +89 -0
- package/dist/directive/phase-sync.d.ts.map +1 -0
- package/dist/directive/phase-sync.js +173 -0
- package/dist/directive/phase-sync.js.map +1 -0
- package/dist/directive-executor.d.ts +21 -223
- package/dist/directive-executor.d.ts.map +1 -1
- package/dist/directive-executor.js +28 -687
- package/dist/directive-executor.js.map +1 -1
- package/dist/focus-engine.d.ts.map +1 -1
- package/dist/focus-engine.js +8 -0
- package/dist/focus-engine.js.map +1 -1
- package/dist/focus-executor.d.ts +29 -8
- package/dist/focus-executor.d.ts.map +1 -1
- package/dist/focus-executor.js +29 -10
- package/dist/focus-executor.js.map +1 -1
- package/dist/focus-stage-lifecycle.d.ts +7 -5
- package/dist/focus-stage-lifecycle.d.ts.map +1 -1
- package/dist/focus-stage-lifecycle.js +11 -6
- package/dist/focus-stage-lifecycle.js.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/pipeline-config.d.ts +13 -0
- package/dist/pipeline-config.d.ts.map +1 -1
- package/dist/pipeline-config.js +15 -0
- package/dist/pipeline-config.js.map +1 -1
- package/dist/resolvers/agent-escalations.d.ts +8 -1
- package/dist/resolvers/agent-escalations.d.ts.map +1 -1
- package/dist/resolvers/agent-escalations.js +25 -22
- package/dist/resolvers/agent-escalations.js.map +1 -1
- package/dist/resolvers/agent-session-summaries.d.ts +8 -1
- package/dist/resolvers/agent-session-summaries.d.ts.map +1 -1
- package/dist/resolvers/agent-session-summaries.js +21 -18
- package/dist/resolvers/agent-session-summaries.js.map +1 -1
- package/dist/resolvers/delivery-acceptance-criteria.d.ts +7 -1
- package/dist/resolvers/delivery-acceptance-criteria.d.ts.map +1 -1
- package/dist/resolvers/delivery-acceptance-criteria.js +14 -11
- package/dist/resolvers/delivery-acceptance-criteria.js.map +1 -1
- package/dist/resolvers/delivery-description.d.ts +7 -1
- package/dist/resolvers/delivery-description.d.ts.map +1 -1
- package/dist/resolvers/delivery-description.js +14 -11
- package/dist/resolvers/delivery-description.js.map +1 -1
- package/dist/resolvers/delivery-issues.d.ts +8 -1
- package/dist/resolvers/delivery-issues.d.ts.map +1 -1
- package/dist/resolvers/delivery-issues.js +51 -48
- package/dist/resolvers/delivery-issues.js.map +1 -1
- package/dist/resolvers/delivery-listing.d.ts +16 -1
- package/dist/resolvers/delivery-listing.d.ts.map +1 -1
- package/dist/resolvers/delivery-listing.js +36 -33
- package/dist/resolvers/delivery-listing.js.map +1 -1
- package/dist/resolvers/delivery-tech-context.d.ts +7 -1
- package/dist/resolvers/delivery-tech-context.d.ts.map +1 -1
- package/dist/resolvers/delivery-tech-context.js +14 -11
- package/dist/resolvers/delivery-tech-context.js.map +1 -1
- package/dist/resolvers/deployment-profile.d.ts +8 -1
- package/dist/resolvers/deployment-profile.d.ts.map +1 -1
- package/dist/resolvers/deployment-profile.js +20 -17
- package/dist/resolvers/deployment-profile.js.map +1 -1
- package/dist/resolvers/focus-anchoring-injections.d.ts +26 -1
- package/dist/resolvers/focus-anchoring-injections.d.ts.map +1 -1
- package/dist/resolvers/focus-anchoring-injections.js +91 -88
- package/dist/resolvers/focus-anchoring-injections.js.map +1 -1
- package/dist/resolvers/focus-context.d.ts +9 -1
- package/dist/resolvers/focus-context.d.ts.map +1 -1
- package/dist/resolvers/focus-context.js +38 -35
- package/dist/resolvers/focus-context.js.map +1 -1
- package/dist/resolvers/focus-injections.d.ts +13 -1
- package/dist/resolvers/focus-injections.d.ts.map +1 -1
- package/dist/resolvers/focus-injections.js +60 -57
- package/dist/resolvers/focus-injections.js.map +1 -1
- package/dist/resolvers/focus-last-review-report.d.ts +2 -1
- package/dist/resolvers/focus-last-review-report.d.ts.map +1 -1
- package/dist/resolvers/focus-last-review-report.js +33 -30
- package/dist/resolvers/focus-last-review-report.js.map +1 -1
- package/dist/resolvers/focus-reality-tree.d.ts +15 -1
- package/dist/resolvers/focus-reality-tree.d.ts.map +1 -1
- package/dist/resolvers/focus-reality-tree.js +35 -32
- package/dist/resolvers/focus-reality-tree.js.map +1 -1
- package/dist/resolvers/git-diff-against-base.d.ts +8 -1
- package/dist/resolvers/git-diff-against-base.d.ts.map +1 -1
- package/dist/resolvers/git-diff-against-base.js +33 -30
- package/dist/resolvers/git-diff-against-base.js.map +1 -1
- package/dist/resolvers/guards-evaluation-results.d.ts +7 -1
- package/dist/resolvers/guards-evaluation-results.d.ts.map +1 -1
- package/dist/resolvers/guards-evaluation-results.js +25 -22
- package/dist/resolvers/guards-evaluation-results.js.map +1 -1
- package/dist/resolvers/index.d.ts +22 -40
- package/dist/resolvers/index.d.ts.map +1 -1
- package/dist/resolvers/index.js +112 -41
- package/dist/resolvers/index.js.map +1 -1
- package/dist/resolvers/loop-context.d.ts +18 -1
- package/dist/resolvers/loop-context.d.ts.map +1 -1
- package/dist/resolvers/loop-context.js +21 -18
- package/dist/resolvers/loop-context.js.map +1 -1
- package/dist/resolvers/loop-delivery-index.d.ts +17 -1
- package/dist/resolvers/loop-delivery-index.d.ts.map +1 -1
- package/dist/resolvers/loop-delivery-index.js +51 -48
- package/dist/resolvers/loop-delivery-index.js.map +1 -1
- package/dist/resolvers/loop-documents.d.ts +9 -1
- package/dist/resolvers/loop-documents.d.ts.map +1 -1
- package/dist/resolvers/loop-documents.js +22 -19
- package/dist/resolvers/loop-documents.js.map +1 -1
- package/dist/resolvers/loop-expected-effects.d.ts +11 -1
- package/dist/resolvers/loop-expected-effects.d.ts.map +1 -1
- package/dist/resolvers/loop-expected-effects.js +53 -50
- package/dist/resolvers/loop-expected-effects.js.map +1 -1
- package/dist/resolvers/loop-frt-statement.d.ts +11 -1
- package/dist/resolvers/loop-frt-statement.d.ts.map +1 -1
- package/dist/resolvers/loop-frt-statement.js +28 -25
- package/dist/resolvers/loop-frt-statement.js.map +1 -1
- package/dist/resolvers/loop-injection.d.ts +10 -1
- package/dist/resolvers/loop-injection.d.ts.map +1 -1
- package/dist/resolvers/loop-injection.js +38 -35
- package/dist/resolvers/loop-injection.js.map +1 -1
- package/dist/resolvers/loop-persona.d.ts +20 -1
- package/dist/resolvers/loop-persona.d.ts.map +1 -1
- package/dist/resolvers/loop-persona.js +20 -17
- package/dist/resolvers/loop-persona.js.map +1 -1
- package/dist/resolvers/loop-questions.d.ts +8 -1
- package/dist/resolvers/loop-questions.d.ts.map +1 -1
- package/dist/resolvers/loop-questions.js +39 -36
- package/dist/resolvers/loop-questions.js.map +1 -1
- package/dist/resolvers/loop-upstream-udes.d.ts +11 -1
- package/dist/resolvers/loop-upstream-udes.d.ts.map +1 -1
- package/dist/resolvers/loop-upstream-udes.js +74 -71
- package/dist/resolvers/loop-upstream-udes.js.map +1 -1
- package/dist/resolvers/prd-context.d.ts +2 -0
- package/dist/resolvers/prd-context.d.ts.map +1 -1
- package/dist/resolvers/prd-context.js +16 -13
- package/dist/resolvers/prd-context.js.map +1 -1
- package/dist/resolvers/prd-persona.d.ts +2 -0
- package/dist/resolvers/prd-persona.d.ts.map +1 -1
- package/dist/resolvers/prd-persona.js +6 -3
- package/dist/resolvers/prd-persona.js.map +1 -1
- package/dist/resolvers/reality-metrics.d.ts +8 -1
- package/dist/resolvers/reality-metrics.d.ts.map +1 -1
- package/dist/resolvers/reality-metrics.js +73 -70
- package/dist/resolvers/reality-metrics.js.map +1 -1
- package/dist/resolvers/reality-projections.d.ts +7 -1
- package/dist/resolvers/reality-projections.d.ts.map +1 -1
- package/dist/resolvers/reality-projections.js +35 -32
- package/dist/resolvers/reality-projections.js.map +1 -1
- package/dist/resolvers/reality-tree-snapshot.d.ts +10 -1
- package/dist/resolvers/reality-tree-snapshot.d.ts.map +1 -1
- package/dist/resolvers/reality-tree-snapshot.js +34 -31
- package/dist/resolvers/reality-tree-snapshot.js.map +1 -1
- package/dist/resolvers/retired-injections.d.ts +10 -1
- package/dist/resolvers/retired-injections.d.ts.map +1 -1
- package/dist/resolvers/retired-injections.js +68 -65
- package/dist/resolvers/retired-injections.js.map +1 -1
- package/dist/resolvers/review-outcomes.d.ts +11 -1
- package/dist/resolvers/review-outcomes.d.ts.map +1 -1
- package/dist/resolvers/review-outcomes.js +27 -24
- package/dist/resolvers/review-outcomes.js.map +1 -1
- package/dist/resolvers/security-advisory.d.ts +2 -1
- package/dist/resolvers/security-advisory.d.ts.map +1 -1
- package/dist/resolvers/security-advisory.js +47 -44
- package/dist/resolvers/security-advisory.js.map +1 -1
- package/dist/resolvers/wiki-search.d.ts +8 -1
- package/dist/resolvers/wiki-search.d.ts.map +1 -1
- package/dist/resolvers/wiki-search.js +17 -14
- package/dist/resolvers/wiki-search.js.map +1 -1
- package/dist/resolvers/wiki-topic.d.ts +9 -1
- package/dist/resolvers/wiki-topic.d.ts.map +1 -1
- package/dist/resolvers/wiki-topic.js +21 -18
- package/dist/resolvers/wiki-topic.js.map +1 -1
- package/dist/resolvers/workflow-stages.d.ts +7 -1
- package/dist/resolvers/workflow-stages.d.ts.map +1 -1
- package/dist/resolvers/workflow-stages.js +20 -17
- package/dist/resolvers/workflow-stages.js.map +1 -1
- package/dist/self-update.d.ts +6 -0
- package/dist/self-update.d.ts.map +1 -1
- package/dist/self-update.js +6 -1
- package/dist/self-update.js.map +1 -1
- package/dist/spawner/index.d.ts +2 -1
- package/dist/spawner/index.d.ts.map +1 -1
- package/dist/spawner/index.js +2 -1
- package/dist/spawner/index.js.map +1 -1
- package/dist/spawner/spawn-team.d.ts +14 -52
- package/dist/spawner/spawn-team.d.ts.map +1 -1
- package/dist/spawner/spawn-team.js +14 -469
- package/dist/spawner/spawn-team.js.map +1 -1
- package/dist/staleness.d.ts +124 -0
- package/dist/staleness.d.ts.map +1 -0
- package/dist/staleness.js +215 -0
- package/dist/staleness.js.map +1 -0
- package/dist/state-cascade.d.ts +3 -2
- package/dist/state-cascade.d.ts.map +1 -1
- package/dist/state-cascade.js +7 -3
- package/dist/state-cascade.js.map +1 -1
- package/dist/types/focus.d.ts +5 -4
- package/dist/types/focus.d.ts.map +1 -1
- package/dist/types/session.d.ts +2 -3
- package/dist/types/session.d.ts.map +1 -1
- package/dist/unified-shell.d.ts.map +1 -1
- package/dist/unified-shell.js +21 -12
- package/dist/unified-shell.js.map +1 -1
- package/package.json +2 -2
- package/dist/session-lifecycle.d.ts +0 -78
- package/dist/session-lifecycle.d.ts.map +0 -1
- package/dist/session-lifecycle.js +0 -382
- package/dist/session-lifecycle.js.map +0 -1
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exit classification phase: how did the team lead process exit?
|
|
3
|
+
*
|
|
4
|
+
* Pure, side-effect-free classification of a team exit into success /
|
|
5
|
+
* controlled stop / failure, plus the exit_category derivation recorded on
|
|
6
|
+
* the session row. First phase of the completion flow in team-completion.ts.
|
|
7
|
+
* Extracted from completion/team-completion.ts; bodies verbatim.
|
|
8
|
+
*/
|
|
9
|
+
import type { FocusTeamState, FocusTeamPhase, ExitCategory } from '../types.js';
|
|
10
|
+
/** Result of classifying how a team lead process exited. */
|
|
11
|
+
export interface TeamExitClassification {
|
|
12
|
+
/** Normalized exit code (null -> 1). */
|
|
13
|
+
exitCode: number;
|
|
14
|
+
/** Node reports a SIGTERM as either signal='SIGTERM' or code=143 (128+15). */
|
|
15
|
+
wasSigterm: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* True when the daemon itself terminated the team because its work was done
|
|
18
|
+
* (shutdownReason='work_complete') -- a lifecycle teardown, NOT a crash.
|
|
19
|
+
*/
|
|
20
|
+
proactivelyTerminated: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* True when the exit should be treated as a SUCCESSFUL completion: a clean
|
|
23
|
+
* code-0 exit, or a proactive lifecycle termination. This is the signal the
|
|
24
|
+
* review-exit handler keys off to auto-approve a clean review's verify
|
|
25
|
+
* delivery -- so a review team that the daemon SIGTERMs as part of normal
|
|
26
|
+
* teardown is NOT mistaken for a failed review.
|
|
27
|
+
*
|
|
28
|
+
* IMPORTANT: `succeeded` is NARROW on purpose -- it stays false for a benign
|
|
29
|
+
* daemon-initiated SIGTERM whose reason is NOT work_complete (deactivated /
|
|
30
|
+
* handoff / teardown / user_stopped). The review auto-approve path depends on
|
|
31
|
+
* that. To label such a controlled stop as a non-error terminal status, use
|
|
32
|
+
* `controlledStop` / `disposition` instead of widening `succeeded`.
|
|
33
|
+
*/
|
|
34
|
+
succeeded: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* True when the daemon itself drove this exit: the team was in the
|
|
37
|
+
* 'shutting_down' phase and the process exited via SIGTERM -- for ANY
|
|
38
|
+
* shutdownReason (work_complete, deactivated, handoff, teardown,
|
|
39
|
+
* user_stopped, or none). Distinguishes a deliberate daemon stop from a
|
|
40
|
+
* genuine crash, WITHOUT widening `succeeded`.
|
|
41
|
+
*/
|
|
42
|
+
controlledStop: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Terminal disposition for the session status label:
|
|
45
|
+
* - 'completed' -- a successful exit (`succeeded`).
|
|
46
|
+
* - 'stopped' -- a controlled daemon stop that was not a success
|
|
47
|
+
* (`controlledStop && !succeeded`).
|
|
48
|
+
* - 'failed' -- a genuine crash / unexpected exit.
|
|
49
|
+
* Maps 1:1 to the agent_sessions status the daemon writes.
|
|
50
|
+
*/
|
|
51
|
+
disposition: 'completed' | 'stopped' | 'failed';
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Classify how a team lead process exited.
|
|
55
|
+
*
|
|
56
|
+
* Pure and side-effect free so the "lifecycle SIGTERM is not a review failure"
|
|
57
|
+
* invariant is unit-testable in isolation. The crux: when the daemon proactively
|
|
58
|
+
* terminates a team because its work is complete, it sets phase='shutting_down'
|
|
59
|
+
* and shutdownReason='work_complete' BEFORE sending SIGTERM. We detect that
|
|
60
|
+
* teardown and classify it as succeeded -- otherwise a clean review team
|
|
61
|
+
* (which commits nothing of its own, then gets SIGTERMed once all deliveries
|
|
62
|
+
* are terminal) would look like a failed exit and its verify delivery would be
|
|
63
|
+
* stranded in `verify` instead of auto-approved to `done`.
|
|
64
|
+
*/
|
|
65
|
+
export declare function classifyTeamExit(params: {
|
|
66
|
+
code: number | null;
|
|
67
|
+
signal: string | null;
|
|
68
|
+
teamPhase: FocusTeamPhase;
|
|
69
|
+
shutdownReason: FocusTeamState['shutdownReason'];
|
|
70
|
+
}): TeamExitClassification;
|
|
71
|
+
/**
|
|
72
|
+
* Derive the `exit_category` to record alongside the session status, given the
|
|
73
|
+
* classifier disposition and the team's shutdown reason.
|
|
74
|
+
*
|
|
75
|
+
* - 'completed' -> 'work_complete' when the daemon stopped the team because its
|
|
76
|
+
* work was done; otherwise null (a plain clean self-exit has no category).
|
|
77
|
+
* - 'stopped' -> the specific controlled-stop reason; any unknown/null reason
|
|
78
|
+
* falls back to 'handoff' (a benign daemon-initiated respawn).
|
|
79
|
+
* - 'failed' -> 'error' (genuine crash / unexpected exit).
|
|
80
|
+
*/
|
|
81
|
+
export declare function deriveExitCategory(disposition: TeamExitClassification['disposition'], shutdownReason: FocusTeamState['shutdownReason']): ExitCategory | null;
|
|
82
|
+
//# sourceMappingURL=exit-classification.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exit-classification.d.ts","sourceRoot":"","sources":["../../src/completion/exit-classification.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIhF,4DAA4D;AAC5D,MAAM,WAAW,sBAAsB;IACrC,wCAAwC;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,UAAU,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,qBAAqB,EAAE,OAAO,CAAC;IAC/B;;;;;;;;;;;;OAYG;IACH,SAAS,EAAE,OAAO,CAAC;IACnB;;;;;;OAMG;IACH,cAAc,EAAE,OAAO,CAAC;IACxB;;;;;;;OAOG;IACH,WAAW,EAAE,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC;CACjD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE;IACvC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,EAAE,cAAc,CAAC;IAC1B,cAAc,EAAE,cAAc,CAAC,gBAAgB,CAAC,CAAC;CAClD,GAAG,sBAAsB,CAezB;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,sBAAsB,CAAC,aAAa,CAAC,EAClD,cAAc,EAAE,cAAc,CAAC,gBAAgB,CAAC,GAC/C,YAAY,GAAG,IAAI,CAerB"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exit classification phase: how did the team lead process exit?
|
|
3
|
+
*
|
|
4
|
+
* Pure, side-effect-free classification of a team exit into success /
|
|
5
|
+
* controlled stop / failure, plus the exit_category derivation recorded on
|
|
6
|
+
* the session row. First phase of the completion flow in team-completion.ts.
|
|
7
|
+
* Extracted from completion/team-completion.ts; bodies verbatim.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Classify how a team lead process exited.
|
|
11
|
+
*
|
|
12
|
+
* Pure and side-effect free so the "lifecycle SIGTERM is not a review failure"
|
|
13
|
+
* invariant is unit-testable in isolation. The crux: when the daemon proactively
|
|
14
|
+
* terminates a team because its work is complete, it sets phase='shutting_down'
|
|
15
|
+
* and shutdownReason='work_complete' BEFORE sending SIGTERM. We detect that
|
|
16
|
+
* teardown and classify it as succeeded -- otherwise a clean review team
|
|
17
|
+
* (which commits nothing of its own, then gets SIGTERMed once all deliveries
|
|
18
|
+
* are terminal) would look like a failed exit and its verify delivery would be
|
|
19
|
+
* stranded in `verify` instead of auto-approved to `done`.
|
|
20
|
+
*/
|
|
21
|
+
export function classifyTeamExit(params) {
|
|
22
|
+
const exitCode = params.code ?? 1;
|
|
23
|
+
const wasSigterm = params.signal === 'SIGTERM' || exitCode === 143;
|
|
24
|
+
const proactivelyTerminated = params.teamPhase === 'shutting_down' &&
|
|
25
|
+
wasSigterm &&
|
|
26
|
+
params.shutdownReason === 'work_complete';
|
|
27
|
+
const succeeded = exitCode === 0 || proactivelyTerminated;
|
|
28
|
+
// A controlled stop is any SIGTERM the daemon sent while the team was already
|
|
29
|
+
// shutting down -- regardless of reason. It is the signal that distinguishes
|
|
30
|
+
// a deliberate daemon teardown from a crash, without touching `succeeded`.
|
|
31
|
+
const controlledStop = params.teamPhase === 'shutting_down' && wasSigterm;
|
|
32
|
+
const disposition = succeeded ? 'completed' : controlledStop ? 'stopped' : 'failed';
|
|
33
|
+
return { exitCode, wasSigterm, proactivelyTerminated, succeeded, controlledStop, disposition };
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Derive the `exit_category` to record alongside the session status, given the
|
|
37
|
+
* classifier disposition and the team's shutdown reason.
|
|
38
|
+
*
|
|
39
|
+
* - 'completed' -> 'work_complete' when the daemon stopped the team because its
|
|
40
|
+
* work was done; otherwise null (a plain clean self-exit has no category).
|
|
41
|
+
* - 'stopped' -> the specific controlled-stop reason; any unknown/null reason
|
|
42
|
+
* falls back to 'handoff' (a benign daemon-initiated respawn).
|
|
43
|
+
* - 'failed' -> 'error' (genuine crash / unexpected exit).
|
|
44
|
+
*/
|
|
45
|
+
export function deriveExitCategory(disposition, shutdownReason) {
|
|
46
|
+
switch (disposition) {
|
|
47
|
+
case 'completed':
|
|
48
|
+
return shutdownReason === 'work_complete' ? 'work_complete' : null;
|
|
49
|
+
case 'stopped':
|
|
50
|
+
switch (shutdownReason) {
|
|
51
|
+
case 'deactivated': return 'deactivated';
|
|
52
|
+
case 'user_stopped': return 'user_stopped';
|
|
53
|
+
case 'handoff': return 'handoff';
|
|
54
|
+
case 'teardown': return 'teardown';
|
|
55
|
+
default: return 'handoff';
|
|
56
|
+
}
|
|
57
|
+
case 'failed':
|
|
58
|
+
return 'error';
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=exit-classification.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exit-classification.js","sourceRoot":"","sources":["../../src/completion/exit-classification.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAkDH;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAKhC;IACC,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC;IAClC,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,KAAK,SAAS,IAAI,QAAQ,KAAK,GAAG,CAAC;IACnE,MAAM,qBAAqB,GACzB,MAAM,CAAC,SAAS,KAAK,eAAe;QACpC,UAAU;QACV,MAAM,CAAC,cAAc,KAAK,eAAe,CAAC;IAC5C,MAAM,SAAS,GAAG,QAAQ,KAAK,CAAC,IAAI,qBAAqB,CAAC;IAC1D,8EAA8E;IAC9E,6EAA6E;IAC7E,2EAA2E;IAC3E,MAAM,cAAc,GAAG,MAAM,CAAC,SAAS,KAAK,eAAe,IAAI,UAAU,CAAC;IAC1E,MAAM,WAAW,GACf,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC;IAClE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,qBAAqB,EAAE,SAAS,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC;AACjG,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAChC,WAAkD,EAClD,cAAgD;IAEhD,QAAQ,WAAW,EAAE,CAAC;QACpB,KAAK,WAAW;YACd,OAAO,cAAc,KAAK,eAAe,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC;QACrE,KAAK,SAAS;YACZ,QAAQ,cAAc,EAAE,CAAC;gBACvB,KAAK,aAAa,CAAC,CAAC,OAAO,aAAa,CAAC;gBACzC,KAAK,cAAc,CAAC,CAAC,OAAO,cAAc,CAAC;gBAC3C,KAAK,SAAS,CAAC,CAAC,OAAO,SAAS,CAAC;gBACjC,KAAK,UAAU,CAAC,CAAC,OAAO,UAAU,CAAC;gBACnC,OAAO,CAAC,CAAC,OAAO,SAAS,CAAC;YAC5B,CAAC;QACH,KAAK,QAAQ;YACX,OAAO,OAAO,CAAC;IACnB,CAAC;AACH,CAAC"}
|
|
@@ -6,16 +6,25 @@
|
|
|
6
6
|
* directory) rather than reaching into individual modules.
|
|
7
7
|
*
|
|
8
8
|
* Modules:
|
|
9
|
-
* - detector.ts
|
|
10
|
-
* - team-completion.ts
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* -
|
|
9
|
+
* - detector.ts -- CompletionDetector (interactive-session idle/complete detection)
|
|
10
|
+
* - team-completion.ts -- handleTeamCompletion: the explicit PHASE SEQUENCER for team exit
|
|
11
|
+
* (classify -> git state -> guards -> status advance -> merge ->
|
|
12
|
+
* CI -> session finalize -> review exit -> terminate)
|
|
13
|
+
* - exit-classification.ts -- pure exit classification (success / controlled stop / crash)
|
|
14
|
+
* - merge-phase.ts -- merge gate, focus->integration merge, CI integration->main
|
|
15
|
+
* - status-advance-phase.ts -- delivery status advancement from issue completion
|
|
16
|
+
* - review-exit-phase.ts -- verify-delivery routing on review exit (auto-approve / verify_failed)
|
|
17
|
+
* - completion-decision.ts -- pure mid-focus handoff vs terminate decision tree
|
|
18
|
+
* - event.ts -- handleCompletionEvent (CompletionDetector event reactions, escalations)
|
|
19
|
+
* - team-lifecycle.ts -- terminate/wait/detect-deactivated team lifecycle helpers
|
|
20
|
+
* - agent-completion.ts -- legacy per-delivery handleAgentCompletion
|
|
14
21
|
*/
|
|
15
22
|
export { CompletionDetector, } from './detector.js';
|
|
16
23
|
export type { CompletionDetectorEvents, CompletionInfo, IdleInfo, } from './detector.js';
|
|
17
24
|
export { isStatusTerminal, isStatusAgentActionable, shouldAttemptMerge, REPORTABLE_DELIVERY_STATUSES, selectWorkedDeliveryIds, attemptFocusMerge, runReviewExitHandler, classifyTeamExit, handleTeamCompletion, advanceDeliveryStatuses, } from './team-completion.js';
|
|
18
25
|
export type { FocusMergeAttemptDeps, FocusMergeAttemptResult, ReviewExitDeps, ReviewExitParams, TeamCompletionParams, TeamExitClassification, AdvanceDeliveryDeps, } from './team-completion.js';
|
|
26
|
+
export { decideCompletionAction, shouldCheckNonAdvanceable, } from './completion-decision.js';
|
|
27
|
+
export type { CompletionAction, CompletionDecisionFacts, } from './completion-decision.js';
|
|
19
28
|
export { PLANNING_NO_DELIVERIES_REASON, NO_PROGRESS_ESCALATION_REASON, NON_ADVANCEABLE_ESCALATION_REASON, NON_ADVANCEABLE_CAUSE, SCOPE_COVERAGE_NO_PROGRESS_LIMIT, escalatePlanningFailure, isDeliveryNonAdvanceable, findNonAdvanceableDelivery, handleCompletionEvent, isInReviewWindow, takeProgressSnapshot, snapshotsEqual, escalateNoProgress, escalateNonAdvanceable, } from './event.js';
|
|
20
29
|
export type { CompletionEventContext, CompletionEventDeps, } from './event.js';
|
|
21
30
|
export { terminateTeam, waitForTeamExit, terminateAllTeams, detectDeactivatedFocuses, checkAndMergeCompletedDeliveries, } from './team-lifecycle.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/completion/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/completion/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,EACL,kBAAkB,GACnB,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,wBAAwB,EACxB,cAAc,EACd,QAAQ,GACT,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,kBAAkB,EAClB,4BAA4B,EAC5B,uBAAuB,EACvB,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,EAChB,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,qBAAqB,EACrB,uBAAuB,EACvB,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,sBAAsB,EACtB,mBAAmB,GACpB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,gBAAgB,EAChB,uBAAuB,GACxB,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EACL,6BAA6B,EAC7B,6BAA6B,EAC7B,iCAAiC,EACjC,qBAAqB,EACrB,gCAAgC,EAChC,uBAAuB,EACvB,wBAAwB,EACxB,0BAA0B,EAC1B,qBAAqB,EACrB,gBAAgB,EAChB,oBAAoB,EACpB,cAAc,EACd,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,sBAAsB,EACtB,mBAAmB,GACpB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,wBAAwB,EACxB,gCAAgC,GACjC,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,uBAAuB,GACxB,MAAM,uBAAuB,CAAC"}
|
package/dist/completion/index.js
CHANGED
|
@@ -6,16 +6,25 @@
|
|
|
6
6
|
* directory) rather than reaching into individual modules.
|
|
7
7
|
*
|
|
8
8
|
* Modules:
|
|
9
|
-
* - detector.ts
|
|
10
|
-
* - team-completion.ts
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* -
|
|
9
|
+
* - detector.ts -- CompletionDetector (interactive-session idle/complete detection)
|
|
10
|
+
* - team-completion.ts -- handleTeamCompletion: the explicit PHASE SEQUENCER for team exit
|
|
11
|
+
* (classify -> git state -> guards -> status advance -> merge ->
|
|
12
|
+
* CI -> session finalize -> review exit -> terminate)
|
|
13
|
+
* - exit-classification.ts -- pure exit classification (success / controlled stop / crash)
|
|
14
|
+
* - merge-phase.ts -- merge gate, focus->integration merge, CI integration->main
|
|
15
|
+
* - status-advance-phase.ts -- delivery status advancement from issue completion
|
|
16
|
+
* - review-exit-phase.ts -- verify-delivery routing on review exit (auto-approve / verify_failed)
|
|
17
|
+
* - completion-decision.ts -- pure mid-focus handoff vs terminate decision tree
|
|
18
|
+
* - event.ts -- handleCompletionEvent (CompletionDetector event reactions, escalations)
|
|
19
|
+
* - team-lifecycle.ts -- terminate/wait/detect-deactivated team lifecycle helpers
|
|
20
|
+
* - agent-completion.ts -- legacy per-delivery handleAgentCompletion
|
|
14
21
|
*/
|
|
15
22
|
// ── Completion detector ──────────────────────────────────────────────
|
|
16
23
|
export { CompletionDetector, } from './detector.js';
|
|
17
24
|
// ── Team completion ──────────────────────────────────────────────────
|
|
18
25
|
export { isStatusTerminal, isStatusAgentActionable, shouldAttemptMerge, REPORTABLE_DELIVERY_STATUSES, selectWorkedDeliveryIds, attemptFocusMerge, runReviewExitHandler, classifyTeamExit, handleTeamCompletion, advanceDeliveryStatuses, } from './team-completion.js';
|
|
26
|
+
// ── Completion decision (pure handoff-vs-terminate tree) ─────────────
|
|
27
|
+
export { decideCompletionAction, shouldCheckNonAdvanceable, } from './completion-decision.js';
|
|
19
28
|
// ── Completion event handler ─────────────────────────────────────────
|
|
20
29
|
export { PLANNING_NO_DELIVERIES_REASON, NO_PROGRESS_ESCALATION_REASON, NON_ADVANCEABLE_ESCALATION_REASON, NON_ADVANCEABLE_CAUSE, SCOPE_COVERAGE_NO_PROGRESS_LIMIT, escalatePlanningFailure, isDeliveryNonAdvanceable, findNonAdvanceableDelivery, handleCompletionEvent, isInReviewWindow, takeProgressSnapshot, snapshotsEqual, escalateNoProgress, escalateNonAdvanceable, } from './event.js';
|
|
21
30
|
// ── Team lifecycle ───────────────────────────────────────────────────
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/completion/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/completion/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,wEAAwE;AACxE,OAAO,EACL,kBAAkB,GACnB,MAAM,eAAe,CAAC;AAOvB,wEAAwE;AACxE,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,kBAAkB,EAClB,4BAA4B,EAC5B,uBAAuB,EACvB,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,EAChB,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,sBAAsB,CAAC;AAW9B,wEAAwE;AACxE,OAAO,EACL,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,0BAA0B,CAAC;AAMlC,wEAAwE;AACxE,OAAO,EACL,6BAA6B,EAC7B,6BAA6B,EAC7B,iCAAiC,EACjC,qBAAqB,EACrB,gCAAgC,EAChC,uBAAuB,EACvB,wBAAwB,EACxB,0BAA0B,EAC1B,qBAAqB,EACrB,gBAAgB,EAChB,oBAAoB,EACpB,cAAc,EACd,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AAMpB,wEAAwE;AACxE,OAAO,EACL,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,wBAAwB,EACxB,gCAAgC,GACjC,MAAM,qBAAqB,CAAC;AAE7B,wEAAwE;AACxE,OAAO,EACL,qBAAqB,GACtB,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merge phase of the team completion flow.
|
|
3
|
+
*
|
|
4
|
+
* Decides whether the focus branch has clean committed work and merges it to
|
|
5
|
+
* integration, escalates per-delivery merge failures, and runs the CI
|
|
6
|
+
* integration -> main backstop merge (with optional CD push). Invoked by the
|
|
7
|
+
* phase sequencer in team-completion.ts after status advancement. Extracted
|
|
8
|
+
* from completion/team-completion.ts; bodies verbatim.
|
|
9
|
+
*/
|
|
10
|
+
import type { DaemonConfig, FocusTeamState } from '../types.js';
|
|
11
|
+
import { mergeFocusBranch } from '../focus-merge.js';
|
|
12
|
+
import { branchHasUnmergedCommits } from '../git.js';
|
|
13
|
+
/**
|
|
14
|
+
* Decide whether to attempt mergeFocusBranch on team exit.
|
|
15
|
+
*
|
|
16
|
+
* The gate asks "does the branch have clean committed work?" rather than
|
|
17
|
+
* "did the team session exit cleanly?" -- so a team that exits via review-
|
|
18
|
+
* cycle SIGTERM, role-clear, daemon crash, or manual termination still gets
|
|
19
|
+
* its committed work propagated to integration.
|
|
20
|
+
*
|
|
21
|
+
* Skip merge when:
|
|
22
|
+
* - The team is still in its planning phase (cancellation mid-planning --
|
|
23
|
+
* nothing scoped, nothing to merge), OR
|
|
24
|
+
* - The team is a read-only audit session (read-only violation; commits, if
|
|
25
|
+
* any, are surfaced separately by the existing readOnly guard), OR
|
|
26
|
+
* - The branch has no committed work ahead of integration (clean exit with
|
|
27
|
+
* no commits, e.g. audit team or planning-only team).
|
|
28
|
+
*
|
|
29
|
+
* Exported for unit testing the gate logic in isolation.
|
|
30
|
+
*/
|
|
31
|
+
export declare function shouldAttemptMerge(teamState: Pick<FocusTeamState, 'planningPhase' | 'readOnly'>, branchHasCommits: boolean): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Statuses for deliveries whose git state should be reported on team
|
|
34
|
+
* completion. Includes 'done' so a focus whose deliveries all reached done
|
|
35
|
+
* before the branch was merged (review SIGTERM, role-clear, deferred merge,
|
|
36
|
+
* etc.) still attempts the merge instead of being short-circuited as
|
|
37
|
+
* "no worked deliveries". Excludes 'queued'/'planning'/'paused'/'cancelled'
|
|
38
|
+
* — those represent work that never started or was abandoned.
|
|
39
|
+
*
|
|
40
|
+
* Exported for unit testing.
|
|
41
|
+
*/
|
|
42
|
+
export declare const REPORTABLE_DELIVERY_STATUSES: ReadonlySet<string>;
|
|
43
|
+
/**
|
|
44
|
+
* Filter delivery list to those whose git state should be reported on team
|
|
45
|
+
* completion. Excludes already-merged deliveries so we don't re-report them.
|
|
46
|
+
*
|
|
47
|
+
* Exported for unit testing the filter logic without invoking handleTeamCompletion.
|
|
48
|
+
*/
|
|
49
|
+
export declare function selectWorkedDeliveryIds(deliveries: readonly {
|
|
50
|
+
id: string;
|
|
51
|
+
executionStatus: string | null;
|
|
52
|
+
}[], alreadyMerged: ReadonlySet<string>): string[];
|
|
53
|
+
export interface FocusMergeAttemptDeps {
|
|
54
|
+
branchHasUnmergedCommits: typeof branchHasUnmergedCommits;
|
|
55
|
+
mergeFocusBranch: typeof mergeFocusBranch;
|
|
56
|
+
}
|
|
57
|
+
export interface FocusMergeAttemptResult {
|
|
58
|
+
attempted: boolean;
|
|
59
|
+
mergeSucceeded: boolean;
|
|
60
|
+
exitReason: string | null;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Decide whether to merge the focus branch and, if so, run the merge.
|
|
64
|
+
*
|
|
65
|
+
* This is the integration of three separate concerns that the merge gate
|
|
66
|
+
* conflated before:
|
|
67
|
+
* 1. Branch state: does the focus branch actually have committed work?
|
|
68
|
+
* 2. Team gate: planningPhase + readOnly safety nets in shouldAttemptMerge.
|
|
69
|
+
* 3. Per-delivery telemetry: workedDeliveryIds is passed through for
|
|
70
|
+
* git-state reporting inside mergeFocusBranch.
|
|
71
|
+
*
|
|
72
|
+
* Returns attempted=false when the gate skips the merge (clean exit with
|
|
73
|
+
* nothing to merge, planning-phase, or read-only). Returns attempted=true
|
|
74
|
+
* with the merge result otherwise.
|
|
75
|
+
*
|
|
76
|
+
* Exported so tests can verify the threading from done-only deliveries +
|
|
77
|
+
* branch-with-commits to a real mergeFocusBranch invocation, without having
|
|
78
|
+
* to mock all of handleTeamCompletion's other side effects.
|
|
79
|
+
*/
|
|
80
|
+
export declare function attemptFocusMerge(config: DaemonConfig, teamState: FocusTeamState, sessionId: string, workedDeliveryIds: string[], deps?: FocusMergeAttemptDeps): Promise<FocusMergeAttemptResult>;
|
|
81
|
+
/**
|
|
82
|
+
* Escalate a failed focus-branch merge for every worked delivery that has not
|
|
83
|
+
* already been merged mid-flight. Fire-and-forget per delivery (a failed
|
|
84
|
+
* escalation logs a warning and never blocks the completion flow).
|
|
85
|
+
*/
|
|
86
|
+
export declare function escalateFailedMergeDeliveries(params: {
|
|
87
|
+
config: DaemonConfig;
|
|
88
|
+
teamState: FocusTeamState;
|
|
89
|
+
sessionId: string;
|
|
90
|
+
workedDeliveryIds: string[];
|
|
91
|
+
mergeExitReason: string | null;
|
|
92
|
+
}): void;
|
|
93
|
+
/**
|
|
94
|
+
* Run the CI integration -> main backstop merge for a completing team.
|
|
95
|
+
*
|
|
96
|
+
* When CI is enabled (default for legacy focuses without the field), always
|
|
97
|
+
* attempt the integration -> main merge at team exit. This is the
|
|
98
|
+
* unconditional backstop: the eager path in focus-team-lifecycle fires when a
|
|
99
|
+
* focus drains mid-flight, but if it didn't (or fired and integration has
|
|
100
|
+
* since moved), the exit path closes the gap. Independent of mergeSucceeded --
|
|
101
|
+
* even when this focus had no new commits, past focuses may have left
|
|
102
|
+
* integration ahead of main. mergeIntegrationToMain no-ops cleanly when
|
|
103
|
+
* integration is already at main. CD additionally pushes.
|
|
104
|
+
*
|
|
105
|
+
* Returns the suffix to append to the session exit reason (always non-empty).
|
|
106
|
+
*/
|
|
107
|
+
export declare function runCiMergeToMain(params: {
|
|
108
|
+
config: DaemonConfig;
|
|
109
|
+
teamState: FocusTeamState;
|
|
110
|
+
sessionId: string;
|
|
111
|
+
mergeSucceeded: boolean;
|
|
112
|
+
workedDeliveryIds: string[];
|
|
113
|
+
}): Promise<string>;
|
|
114
|
+
//# sourceMappingURL=merge-phase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge-phase.d.ts","sourceRoot":"","sources":["../../src/completion/merge-phase.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAEhE,OAAO,EAAE,gBAAgB,EAAyB,MAAM,mBAAmB,CAAC;AAI5E,OAAO,EAAE,wBAAwB,EAAE,MAAM,WAAW,CAAC;AAIrD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,IAAI,CAAC,cAAc,EAAE,eAAe,GAAG,UAAU,CAAC,EAC7D,gBAAgB,EAAE,OAAO,GACxB,OAAO,CAIT;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,4BAA4B,EAAE,WAAW,CAAC,MAAM,CAI3D,CAAC;AAEH;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,SAAS;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EAAE,EACrE,aAAa,EAAE,WAAW,CAAC,MAAM,CAAC,GACjC,MAAM,EAAE,CAIV;AAID,MAAM,WAAW,qBAAqB;IACpC,wBAAwB,EAAE,OAAO,wBAAwB,CAAC;IAC1D,gBAAgB,EAAE,OAAO,gBAAgB,CAAC;CAC3C;AAED,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,EAAE,OAAO,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,cAAc,EACzB,SAAS,EAAE,MAAM,EACjB,iBAAiB,EAAE,MAAM,EAAE,EAC3B,IAAI,GAAE,qBAGL,GACA,OAAO,CAAC,uBAAuB,CAAC,CAqBlC;AAID;;;;GAIG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE;IACpD,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,EAAE,cAAc,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC,GAAG,IAAI,CAiBP;AAID;;;;;;;;;;;;;GAaG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE;IAC7C,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,EAAE,cAAc,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,OAAO,CAAC;IACxB,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B,GAAG,OAAO,CAAC,MAAM,CAAC,CAmElB"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merge phase of the team completion flow.
|
|
3
|
+
*
|
|
4
|
+
* Decides whether the focus branch has clean committed work and merges it to
|
|
5
|
+
* integration, escalates per-delivery merge failures, and runs the CI
|
|
6
|
+
* integration -> main backstop merge (with optional CD push). Invoked by the
|
|
7
|
+
* phase sequencer in team-completion.ts after status advancement. Extracted
|
|
8
|
+
* from completion/team-completion.ts; bodies verbatim.
|
|
9
|
+
*/
|
|
10
|
+
import { reportGitState } from '../supabase.js';
|
|
11
|
+
import { mergeFocusBranch, escalateMergeConflict } from '../focus-merge.js';
|
|
12
|
+
import { mergeIntegrationToMain } from '../git-merge.js';
|
|
13
|
+
import { resolveCiDecision } from '../pipeline-config.js';
|
|
14
|
+
import { fileCdPushEscalation, shouldFileCdPushEscalation } from '../ci-escalation.js';
|
|
15
|
+
import { branchHasUnmergedCommits } from '../git.js';
|
|
16
|
+
// ── Merge gate ───────────────────────────────────────────────────────
|
|
17
|
+
/**
|
|
18
|
+
* Decide whether to attempt mergeFocusBranch on team exit.
|
|
19
|
+
*
|
|
20
|
+
* The gate asks "does the branch have clean committed work?" rather than
|
|
21
|
+
* "did the team session exit cleanly?" -- so a team that exits via review-
|
|
22
|
+
* cycle SIGTERM, role-clear, daemon crash, or manual termination still gets
|
|
23
|
+
* its committed work propagated to integration.
|
|
24
|
+
*
|
|
25
|
+
* Skip merge when:
|
|
26
|
+
* - The team is still in its planning phase (cancellation mid-planning --
|
|
27
|
+
* nothing scoped, nothing to merge), OR
|
|
28
|
+
* - The team is a read-only audit session (read-only violation; commits, if
|
|
29
|
+
* any, are surfaced separately by the existing readOnly guard), OR
|
|
30
|
+
* - The branch has no committed work ahead of integration (clean exit with
|
|
31
|
+
* no commits, e.g. audit team or planning-only team).
|
|
32
|
+
*
|
|
33
|
+
* Exported for unit testing the gate logic in isolation.
|
|
34
|
+
*/
|
|
35
|
+
export function shouldAttemptMerge(teamState, branchHasCommits) {
|
|
36
|
+
if (teamState.planningPhase)
|
|
37
|
+
return false;
|
|
38
|
+
if (teamState.readOnly)
|
|
39
|
+
return false;
|
|
40
|
+
return branchHasCommits;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Statuses for deliveries whose git state should be reported on team
|
|
44
|
+
* completion. Includes 'done' so a focus whose deliveries all reached done
|
|
45
|
+
* before the branch was merged (review SIGTERM, role-clear, deferred merge,
|
|
46
|
+
* etc.) still attempts the merge instead of being short-circuited as
|
|
47
|
+
* "no worked deliveries". Excludes 'queued'/'planning'/'paused'/'cancelled'
|
|
48
|
+
* — those represent work that never started or was abandoned.
|
|
49
|
+
*
|
|
50
|
+
* Exported for unit testing.
|
|
51
|
+
*/
|
|
52
|
+
export const REPORTABLE_DELIVERY_STATUSES = new Set([
|
|
53
|
+
'coding',
|
|
54
|
+
'verify',
|
|
55
|
+
'done',
|
|
56
|
+
]);
|
|
57
|
+
/**
|
|
58
|
+
* Filter delivery list to those whose git state should be reported on team
|
|
59
|
+
* completion. Excludes already-merged deliveries so we don't re-report them.
|
|
60
|
+
*
|
|
61
|
+
* Exported for unit testing the filter logic without invoking handleTeamCompletion.
|
|
62
|
+
*/
|
|
63
|
+
export function selectWorkedDeliveryIds(deliveries, alreadyMerged) {
|
|
64
|
+
return deliveries
|
|
65
|
+
.filter(d => REPORTABLE_DELIVERY_STATUSES.has(d.executionStatus ?? '') && !alreadyMerged.has(d.id))
|
|
66
|
+
.map(d => d.id);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Decide whether to merge the focus branch and, if so, run the merge.
|
|
70
|
+
*
|
|
71
|
+
* This is the integration of three separate concerns that the merge gate
|
|
72
|
+
* conflated before:
|
|
73
|
+
* 1. Branch state: does the focus branch actually have committed work?
|
|
74
|
+
* 2. Team gate: planningPhase + readOnly safety nets in shouldAttemptMerge.
|
|
75
|
+
* 3. Per-delivery telemetry: workedDeliveryIds is passed through for
|
|
76
|
+
* git-state reporting inside mergeFocusBranch.
|
|
77
|
+
*
|
|
78
|
+
* Returns attempted=false when the gate skips the merge (clean exit with
|
|
79
|
+
* nothing to merge, planning-phase, or read-only). Returns attempted=true
|
|
80
|
+
* with the merge result otherwise.
|
|
81
|
+
*
|
|
82
|
+
* Exported so tests can verify the threading from done-only deliveries +
|
|
83
|
+
* branch-with-commits to a real mergeFocusBranch invocation, without having
|
|
84
|
+
* to mock all of handleTeamCompletion's other side effects.
|
|
85
|
+
*/
|
|
86
|
+
export async function attemptFocusMerge(config, teamState, sessionId, workedDeliveryIds, deps = {
|
|
87
|
+
branchHasUnmergedCommits,
|
|
88
|
+
mergeFocusBranch,
|
|
89
|
+
}) {
|
|
90
|
+
const branchHasCommits = deps.branchHasUnmergedCommits(teamState.branchName, config.integrationBranch, config.repoPath);
|
|
91
|
+
if (!shouldAttemptMerge(teamState, branchHasCommits)) {
|
|
92
|
+
return { attempted: false, mergeSucceeded: false, exitReason: null };
|
|
93
|
+
}
|
|
94
|
+
const mergeResult = await deps.mergeFocusBranch(config, teamState, sessionId, teamState.branchName, workedDeliveryIds);
|
|
95
|
+
return {
|
|
96
|
+
attempted: true,
|
|
97
|
+
mergeSucceeded: mergeResult.mergeSucceeded,
|
|
98
|
+
exitReason: mergeResult.exitReason ?? null,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
// ── Merge-failure escalation ─────────────────────────────────────────
|
|
102
|
+
/**
|
|
103
|
+
* Escalate a failed focus-branch merge for every worked delivery that has not
|
|
104
|
+
* already been merged mid-flight. Fire-and-forget per delivery (a failed
|
|
105
|
+
* escalation logs a warning and never blocks the completion flow).
|
|
106
|
+
*/
|
|
107
|
+
export function escalateFailedMergeDeliveries(params) {
|
|
108
|
+
const { config, teamState, sessionId, workedDeliveryIds, mergeExitReason } = params;
|
|
109
|
+
for (const deliveryId of workedDeliveryIds) {
|
|
110
|
+
if (!teamState.mergedDeliveryIds.has(deliveryId)) {
|
|
111
|
+
escalateMergeConflict({
|
|
112
|
+
organizationId: teamState.organizationId,
|
|
113
|
+
sessionId,
|
|
114
|
+
deliveryId,
|
|
115
|
+
deliveryName: teamState.focusName,
|
|
116
|
+
branchName: teamState.branchName,
|
|
117
|
+
integrationBranch: config.integrationBranch,
|
|
118
|
+
mergeError: mergeExitReason ?? 'unknown',
|
|
119
|
+
}).catch(err => console.warn(`[focus-executor] escalateMergeConflict failed for ${deliveryId}:`, err.message));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// ── CI: merge integration → main ──────────────────────────────────────
|
|
124
|
+
/**
|
|
125
|
+
* Run the CI integration -> main backstop merge for a completing team.
|
|
126
|
+
*
|
|
127
|
+
* When CI is enabled (default for legacy focuses without the field), always
|
|
128
|
+
* attempt the integration -> main merge at team exit. This is the
|
|
129
|
+
* unconditional backstop: the eager path in focus-team-lifecycle fires when a
|
|
130
|
+
* focus drains mid-flight, but if it didn't (or fired and integration has
|
|
131
|
+
* since moved), the exit path closes the gap. Independent of mergeSucceeded --
|
|
132
|
+
* even when this focus had no new commits, past focuses may have left
|
|
133
|
+
* integration ahead of main. mergeIntegrationToMain no-ops cleanly when
|
|
134
|
+
* integration is already at main. CD additionally pushes.
|
|
135
|
+
*
|
|
136
|
+
* Returns the suffix to append to the session exit reason (always non-empty).
|
|
137
|
+
*/
|
|
138
|
+
export async function runCiMergeToMain(params) {
|
|
139
|
+
const { config, teamState, sessionId, mergeSucceeded, workedDeliveryIds } = params;
|
|
140
|
+
const focusName = teamState.focusName;
|
|
141
|
+
const ciDecision = resolveCiDecision(teamState.pipelineConfig);
|
|
142
|
+
if (!ciDecision.shouldMerge) {
|
|
143
|
+
console.log(`[CI] Skipping integration→main merge for focus ${teamState.focusId} ("${focusName}"): ci.enabled=false`);
|
|
144
|
+
return ' CI skipped (ci.enabled=false).';
|
|
145
|
+
}
|
|
146
|
+
const { pushToRemote, mergeStrategy } = ciDecision;
|
|
147
|
+
const ciLabel = pushToRemote ? 'CI+CD' : 'CI';
|
|
148
|
+
console.log(`[${ciLabel}] Merging integration to main for "${focusName}" (strategy=${mergeStrategy})${pushToRemote ? ' (will push to remote)' : ''}`);
|
|
149
|
+
try {
|
|
150
|
+
const ciResult = await mergeIntegrationToMain({
|
|
151
|
+
config,
|
|
152
|
+
focusId: teamState.focusId,
|
|
153
|
+
focusName,
|
|
154
|
+
pushToRemote,
|
|
155
|
+
mergeStrategy,
|
|
156
|
+
});
|
|
157
|
+
if (ciResult.success) {
|
|
158
|
+
if (ciResult.pushedTo) {
|
|
159
|
+
console.log(`[${ciLabel}] Pushed main to ${ciResult.pushedTo.name} (${ciResult.pushedTo.url}) for focus ${teamState.focusId} ("${focusName}")`);
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
console.log(`[${ciLabel}] Successfully merged integration to main for focus ${teamState.focusId} ("${focusName}")`);
|
|
163
|
+
}
|
|
164
|
+
// Report merged_to_main / pushed_to_remote for every delivery on
|
|
165
|
+
// integration. That's mid-flight-merged deliveries plus, if this
|
|
166
|
+
// exit's focus→integration merge succeeded, the just-merged ones.
|
|
167
|
+
// Failed focus merges leave workedDeliveryIds off integration —
|
|
168
|
+
// exclude them so we don't lie about where they landed.
|
|
169
|
+
const onIntegration = new Set(teamState.mergedDeliveryIds);
|
|
170
|
+
if (mergeSucceeded) {
|
|
171
|
+
for (const id of workedDeliveryIds)
|
|
172
|
+
onIntegration.add(id);
|
|
173
|
+
}
|
|
174
|
+
const newState = ciResult.pushedTo ? 'pushed_to_remote' : 'merged_to_main';
|
|
175
|
+
for (const deliveryId of onIntegration) {
|
|
176
|
+
reportGitState(deliveryId, newState).catch(err => console.warn(`[${ciLabel}] reportGitState ${newState} failed for ${deliveryId}:`, err.message));
|
|
177
|
+
}
|
|
178
|
+
return ` ${ciLabel}: merged to main${ciResult.pushedTo ? ' and pushed to remote' : ''}.`;
|
|
179
|
+
}
|
|
180
|
+
console.error(`[${ciLabel}] Failed to merge integration to main for "${focusName}": ${ciResult.error}`);
|
|
181
|
+
if (shouldFileCdPushEscalation(pushToRemote, ciResult)) {
|
|
182
|
+
await fileCdPushEscalation({
|
|
183
|
+
organizationId: teamState.organizationId,
|
|
184
|
+
sessionId,
|
|
185
|
+
focusId: teamState.focusId,
|
|
186
|
+
focusName,
|
|
187
|
+
integrationBranch: config.integrationBranch,
|
|
188
|
+
pushError: ciResult.error,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
return ` ${ciLabel} failed: ${ciResult.error}`;
|
|
192
|
+
}
|
|
193
|
+
catch (err) {
|
|
194
|
+
console.error(`[${ciLabel}] Error merging integration to main for "${focusName}":`, err.message);
|
|
195
|
+
return ` ${ciLabel} error: ${err.message}`;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=merge-phase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge-phase.js","sourceRoot":"","sources":["../../src/completion/merge-phase.ts"],"names":[],"mappings":"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"}
|