@telora/daemon 0.20.32 → 0.20.54
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 +2 -2
- package/dist/agent-state.d.ts +4 -6
- package/dist/agent-state.d.ts.map +1 -1
- package/dist/agent-state.js +4 -10
- package/dist/agent-state.js.map +1 -1
- package/dist/branch-status.d.ts +25 -3
- package/dist/branch-status.d.ts.map +1 -1
- package/dist/branch-status.js +130 -59
- package/dist/branch-status.js.map +1 -1
- package/dist/completion/completion-decision.d.ts +29 -3
- package/dist/completion/completion-decision.d.ts.map +1 -1
- package/dist/completion/completion-decision.js +15 -3
- package/dist/completion/completion-decision.js.map +1 -1
- package/dist/completion/event-entry-phases.d.ts +57 -0
- package/dist/completion/event-entry-phases.d.ts.map +1 -0
- package/dist/completion/event-entry-phases.js +205 -0
- package/dist/completion/event-entry-phases.js.map +1 -0
- package/dist/completion/event-phases.d.ts +14 -42
- package/dist/completion/event-phases.d.ts.map +1 -1
- package/dist/completion/event-phases.js +63 -190
- package/dist/completion/event-phases.js.map +1 -1
- package/dist/completion/event.d.ts +11 -1
- package/dist/completion/event.d.ts.map +1 -1
- package/dist/completion/event.js +5 -2
- package/dist/completion/event.js.map +1 -1
- package/dist/completion/index.d.ts +0 -3
- package/dist/completion/index.d.ts.map +1 -1
- package/dist/completion/index.js +0 -3
- package/dist/completion/index.js.map +1 -1
- package/dist/completion/review-exit-phase.d.ts +2 -1
- package/dist/completion/review-exit-phase.d.ts.map +1 -1
- package/dist/completion/review-exit-phase.js +41 -1
- package/dist/completion/review-exit-phase.js.map +1 -1
- package/dist/completion/status-advance-phase.d.ts +2 -0
- package/dist/completion/status-advance-phase.d.ts.map +1 -1
- package/dist/completion/status-advance-phase.js +14 -28
- package/dist/completion/status-advance-phase.js.map +1 -1
- package/dist/completion/team-completion.js +1 -1
- package/dist/completion/team-completion.js.map +1 -1
- package/dist/completion/terminated-work-reconcile.d.ts.map +1 -1
- package/dist/completion/terminated-work-reconcile.js +10 -0
- package/dist/completion/terminated-work-reconcile.js.map +1 -1
- package/dist/constants.d.ts +0 -8
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +0 -8
- package/dist/constants.js.map +1 -1
- package/dist/delivery-close-actions.d.ts +39 -0
- package/dist/delivery-close-actions.d.ts.map +1 -0
- package/dist/delivery-close-actions.js +53 -0
- package/dist/delivery-close-actions.js.map +1 -0
- package/dist/delivery-lifecycle.d.ts +11 -0
- package/dist/delivery-lifecycle.d.ts.map +1 -1
- package/dist/delivery-lifecycle.js +13 -14
- package/dist/delivery-lifecycle.js.map +1 -1
- package/dist/delivery-reconciler.d.ts +18 -4
- package/dist/delivery-reconciler.d.ts.map +1 -1
- package/dist/delivery-reconciler.js +18 -4
- package/dist/delivery-reconciler.js.map +1 -1
- package/dist/directive-executor.d.ts +1 -1
- package/dist/directive-executor.js +1 -1
- package/dist/discovery-fetch.d.ts +76 -0
- package/dist/discovery-fetch.d.ts.map +1 -0
- package/dist/discovery-fetch.js +206 -0
- package/dist/discovery-fetch.js.map +1 -0
- package/dist/discovery-poll.d.ts +1 -51
- package/dist/discovery-poll.d.ts.map +1 -1
- package/dist/discovery-poll.js +10 -192
- package/dist/discovery-poll.js.map +1 -1
- package/dist/drain-teardown.d.ts +11 -6
- package/dist/drain-teardown.d.ts.map +1 -1
- package/dist/drain-teardown.js +3 -2
- package/dist/drain-teardown.js.map +1 -1
- package/dist/focus-branch-ahead.d.ts +42 -0
- package/dist/focus-branch-ahead.d.ts.map +1 -0
- package/dist/focus-branch-ahead.js +45 -0
- package/dist/focus-branch-ahead.js.map +1 -0
- package/dist/focus-engine.d.ts.map +1 -1
- package/dist/focus-engine.js +21 -43
- package/dist/focus-engine.js.map +1 -1
- package/dist/focus-executor.js +2 -2
- package/dist/focus-executor.js.map +1 -1
- package/dist/focus-lifecycle.d.ts.map +1 -1
- package/dist/focus-lifecycle.js +32 -3
- package/dist/focus-lifecycle.js.map +1 -1
- package/dist/focus-loop.d.ts +34 -12
- package/dist/focus-loop.d.ts.map +1 -1
- package/dist/focus-loop.js +78 -15
- package/dist/focus-loop.js.map +1 -1
- package/dist/focus-merge.d.ts.map +1 -1
- package/dist/focus-merge.js +6 -1
- package/dist/focus-merge.js.map +1 -1
- package/dist/focus-phase.d.ts +18 -3
- package/dist/focus-phase.d.ts.map +1 -1
- package/dist/focus-phase.js +85 -31
- package/dist/focus-phase.js.map +1 -1
- package/dist/focus-prompt-builder.d.ts.map +1 -1
- package/dist/focus-prompt-builder.js +8 -0
- package/dist/focus-prompt-builder.js.map +1 -1
- package/dist/focus-provisioning.d.ts.map +1 -1
- package/dist/focus-provisioning.js +4 -0
- package/dist/focus-provisioning.js.map +1 -1
- package/dist/focus-stage-lifecycle/planning-release.d.ts +35 -17
- package/dist/focus-stage-lifecycle/planning-release.d.ts.map +1 -1
- package/dist/focus-stage-lifecycle/planning-release.js +53 -22
- package/dist/focus-stage-lifecycle/planning-release.js.map +1 -1
- package/dist/focus-worktree-state.d.ts +17 -6
- package/dist/focus-worktree-state.d.ts.map +1 -1
- package/dist/focus-worktree-state.js +21 -11
- package/dist/focus-worktree-state.js.map +1 -1
- package/dist/guard-engine.d.ts +1 -2
- package/dist/guard-engine.d.ts.map +1 -1
- package/dist/guard-engine.js +1 -2
- package/dist/guard-engine.js.map +1 -1
- package/dist/health-events.d.ts +10 -0
- package/dist/health-events.d.ts.map +1 -0
- package/dist/health-events.js +10 -0
- package/dist/health-events.js.map +1 -0
- package/dist/heartbeat.d.ts +19 -0
- package/dist/heartbeat.d.ts.map +1 -1
- package/dist/heartbeat.js +58 -22
- package/dist/heartbeat.js.map +1 -1
- package/dist/host-control/catalog.d.ts.map +1 -1
- package/dist/host-control/catalog.js +4 -1
- package/dist/host-control/catalog.js.map +1 -1
- package/dist/host-control/client.d.ts +3 -4
- package/dist/host-control/client.d.ts.map +1 -1
- package/dist/host-control/client.js +4 -5
- package/dist/host-control/client.js.map +1 -1
- package/dist/listener-auto-advance.d.ts +2 -1
- package/dist/listener-auto-advance.d.ts.map +1 -1
- package/dist/listener-auto-advance.js +36 -40
- package/dist/listener-auto-advance.js.map +1 -1
- package/dist/listener.d.ts +2 -7
- package/dist/listener.d.ts.map +1 -1
- package/dist/listener.js +11 -9
- package/dist/listener.js.map +1 -1
- package/dist/operator-hold.d.ts +66 -0
- package/dist/operator-hold.d.ts.map +1 -0
- package/dist/operator-hold.js +99 -0
- package/dist/operator-hold.js.map +1 -0
- package/dist/poll-trigger.d.ts +28 -0
- package/dist/poll-trigger.d.ts.map +1 -0
- package/dist/poll-trigger.js +31 -0
- package/dist/poll-trigger.js.map +1 -0
- package/dist/prompt-listing.js +6 -0
- package/dist/prompt-listing.js.map +1 -1
- package/dist/prompt-sections/execution-sections.d.ts.map +1 -1
- package/dist/prompt-sections/execution-sections.js +24 -0
- package/dist/prompt-sections/execution-sections.js.map +1 -1
- package/dist/queries/context-lock-queries.d.ts.map +1 -1
- package/dist/queries/context-lock-queries.js +4 -1
- package/dist/queries/context-lock-queries.js.map +1 -1
- package/dist/queries/deliveries.d.ts +17 -0
- package/dist/queries/deliveries.d.ts.map +1 -1
- package/dist/queries/deliveries.js.map +1 -1
- package/dist/queries/issues.d.ts +98 -0
- package/dist/queries/issues.d.ts.map +1 -1
- package/dist/queries/issues.js +135 -0
- package/dist/queries/issues.js.map +1 -1
- package/dist/queries/schemas.d.ts +3 -3
- package/dist/spawn/worktree-session.d.ts.map +1 -1
- package/dist/spawn/worktree-session.js +2 -0
- package/dist/spawn/worktree-session.js.map +1 -1
- package/dist/spawner/index.d.ts +7 -9
- package/dist/spawner/index.d.ts.map +1 -1
- package/dist/spawner/index.js +13 -11
- package/dist/spawner/index.js.map +1 -1
- package/dist/spawner/lifecycle.d.ts +1 -18
- package/dist/spawner/lifecycle.d.ts.map +1 -1
- package/dist/spawner/lifecycle.js +1 -54
- package/dist/spawner/lifecycle.js.map +1 -1
- package/dist/spawner/liveness.d.ts +5 -14
- package/dist/spawner/liveness.d.ts.map +1 -1
- package/dist/spawner/liveness.js +5 -67
- package/dist/spawner/liveness.js.map +1 -1
- package/dist/spawner/state.d.ts +8 -20
- package/dist/spawner/state.d.ts.map +1 -1
- package/dist/spawner/state.js +8 -34
- package/dist/spawner/state.js.map +1 -1
- package/dist/types/focus.d.ts +9 -0
- package/dist/types/focus.d.ts.map +1 -1
- package/dist/types/session.d.ts +0 -44
- package/dist/types/session.d.ts.map +1 -1
- package/dist/unified-shell.d.ts.map +1 -1
- package/dist/unified-shell.js +8 -0
- package/dist/unified-shell.js.map +1 -1
- package/package.json +1 -2
- package/dist/completion/agent-completion.d.ts +0 -48
- package/dist/completion/agent-completion.d.ts.map +0 -1
- package/dist/completion/agent-completion.js +0 -205
- package/dist/completion/agent-completion.js.map +0 -1
- package/dist/delivery-guards.d.ts +0 -41
- package/dist/delivery-guards.d.ts.map +0 -1
- package/dist/delivery-guards.js +0 -200
- package/dist/delivery-guards.js.map +0 -1
- package/dist/spawner/spawn-team.d.ts +0 -20
- package/dist/spawner/spawn-team.d.ts.map +0 -1
- package/dist/spawner/spawn-team.js +0 -19
- package/dist/spawner/spawn-team.js.map +0 -1
- package/dist/spawner/timeout.d.ts +0 -32
- package/dist/spawner/timeout.d.ts.map +0 -1
- package/dist/spawner/timeout.js +0 -126
- package/dist/spawner/timeout.js.map +0 -1
package/build-info.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"commitSha": "
|
|
3
|
-
"builtAt": "2026-07-
|
|
2
|
+
"commitSha": "ef44c4aab",
|
|
3
|
+
"builtAt": "2026-07-26T13:06:17.133Z",
|
|
4
4
|
"expectedMigrations": [
|
|
5
5
|
"20250829113330_create_org_nodes_table.sql",
|
|
6
6
|
"20250829113402_fix_function_security_search_path.sql",
|
package/dist/agent-state.d.ts
CHANGED
|
@@ -3,15 +3,13 @@
|
|
|
3
3
|
* heartbeat.ts and spawner.ts by centralizing state that both modules need.
|
|
4
4
|
*
|
|
5
5
|
* Contains:
|
|
6
|
-
* - Running agents map (read by heartbeat, written by spawner)
|
|
7
6
|
* - Session completion counters (written by spawner/completion-handler, read by heartbeat)
|
|
8
7
|
* - Activity tracking (written by spawner/listener, read by heartbeat)
|
|
8
|
+
*
|
|
9
|
+
* The legacy per-delivery `runningAgents` map was removed: the only live spawn
|
|
10
|
+
* path (`spawnFocusTeam`) tracks team leads in `activeTeams`, reaped by the
|
|
11
|
+
* single `reapWorkerFleet` teardown. See packages/daemon/CLAUDE.md.
|
|
9
12
|
*/
|
|
10
|
-
import type { RunningAgent } from './types.js';
|
|
11
|
-
/**
|
|
12
|
-
* Get map of running agents.
|
|
13
|
-
*/
|
|
14
|
-
export declare function getRunningAgents(): Map<string, RunningAgent>;
|
|
15
13
|
/**
|
|
16
14
|
* Record a completed session (called by spawner when an agent finishes).
|
|
17
15
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-state.d.ts","sourceRoot":"","sources":["../src/agent-state.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"agent-state.d.ts","sourceRoot":"","sources":["../src/agent-state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAQH;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAIzE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI;IACpC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;CACnB,CAEA;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE;IAC3C,qBAAqB,EAAE,MAAM,CAAC;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,IAAI,CAIP;AAMD;;;GAGG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAExC"}
|
package/dist/agent-state.js
CHANGED
|
@@ -3,19 +3,13 @@
|
|
|
3
3
|
* heartbeat.ts and spawner.ts by centralizing state that both modules need.
|
|
4
4
|
*
|
|
5
5
|
* Contains:
|
|
6
|
-
* - Running agents map (read by heartbeat, written by spawner)
|
|
7
6
|
* - Session completion counters (written by spawner/completion-handler, read by heartbeat)
|
|
8
7
|
* - Activity tracking (written by spawner/listener, read by heartbeat)
|
|
8
|
+
*
|
|
9
|
+
* The legacy per-delivery `runningAgents` map was removed: the only live spawn
|
|
10
|
+
* path (`spawnFocusTeam`) tracks team leads in `activeTeams`, reaped by the
|
|
11
|
+
* single `reapWorkerFleet` teardown. See packages/daemon/CLAUDE.md.
|
|
9
12
|
*/
|
|
10
|
-
// ── Running agents map ──────────────────────────────────────────────
|
|
11
|
-
/** Running agents map: sessionId -> RunningAgent */
|
|
12
|
-
const runningAgents = new Map();
|
|
13
|
-
/**
|
|
14
|
-
* Get map of running agents.
|
|
15
|
-
*/
|
|
16
|
-
export function getRunningAgents() {
|
|
17
|
-
return runningAgents;
|
|
18
|
-
}
|
|
19
13
|
// ── Session completion counters ─────────────────────────────────────
|
|
20
14
|
let completedSessionCount = 0;
|
|
21
15
|
let totalTokensUsed = 0;
|
package/dist/agent-state.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-state.js","sourceRoot":"","sources":["../src/agent-state.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"agent-state.js","sourceRoot":"","sources":["../src/agent-state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,uEAAuE;AAEvE,IAAI,qBAAqB,GAAG,CAAC,CAAC;AAC9B,IAAI,eAAe,GAAG,CAAC,CAAC;AACxB,IAAI,SAAS,GAAG,CAAC,CAAC;AAElB;;GAEG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAAc,EAAE,IAAY;IACjE,qBAAqB,EAAE,CAAC;IACxB,eAAe,IAAI,MAAM,CAAC;IAC1B,SAAS,IAAI,IAAI,CAAC;AACpB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB;IAKhC,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,SAAS,EAAE,CAAC;AAC/D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAIlC;IACC,qBAAqB,GAAG,QAAQ,CAAC,qBAAqB,CAAC;IACvD,eAAe,GAAG,QAAQ,CAAC,eAAe,CAAC;IAC3C,SAAS,GAAG,QAAQ,CAAC,SAAS,CAAC;AACjC,CAAC;AAED,uEAAuE;AAEvE,IAAI,cAAc,GAAG,IAAI,IAAI,EAAE,CAAC;AAEhC;;;GAGG;AACH,MAAM,UAAU,cAAc;IAC5B,cAAc,GAAG,IAAI,IAAI,EAAE,CAAC;AAC9B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,cAAc,CAAC;AACxB,CAAC"}
|
package/dist/branch-status.d.ts
CHANGED
|
@@ -7,10 +7,30 @@
|
|
|
7
7
|
* 3. Each focus worktree vs integration
|
|
8
8
|
*
|
|
9
9
|
* Results ride in the heartbeat metadata field (no new tables).
|
|
10
|
+
*
|
|
11
|
+
* Multi-product: computeBranchStatus is called once per configured product
|
|
12
|
+
* with a product-scoped config (configForProduct). The focus worktree map
|
|
13
|
+
* spans all products, so this module scopes it by each entry's productId and
|
|
14
|
+
* runs git against the entry's own repoPath — evaluating a worktree against
|
|
15
|
+
* a repository that does not own it is unrepresentable here. All caches are
|
|
16
|
+
* keyed per product so one product's tick cannot evict another's state.
|
|
17
|
+
*
|
|
18
|
+
* Failure semantics (two distinct kinds, deliberately kept apart):
|
|
19
|
+
* - TRANSIENT git failures (lock contention, mid-rebase, timeouts) fall
|
|
20
|
+
* back to the last good cached status without raising anything — this
|
|
21
|
+
* tolerance predates this module split and prevents UI flicker.
|
|
22
|
+
* - PERMANENT failures (unknown revision, not a git repository, bad
|
|
23
|
+
* object) mean the branch we believe exists cannot be resolved where we
|
|
24
|
+
* looked: an attribution error, not contention. These are surfaced via
|
|
25
|
+
* a healthEvent + error log (once per focus per daemon run) instead of
|
|
26
|
+
* silently rendering identically to "no worktree". A worktree entry in
|
|
27
|
+
* the map IS the claim that its branch should exist; a legitimately
|
|
28
|
+
* deleted branch is removed from the map (removeFocusWorktree) before
|
|
29
|
+
* ever being evaluated here, so ordinary deletions raise no events.
|
|
10
30
|
*/
|
|
11
31
|
import type { DaemonConfig } from './types.js';
|
|
12
32
|
import type { BranchMonitorEntry } from './queries/products.js';
|
|
13
|
-
/** Reset
|
|
33
|
+
/** Reset all caches. Exported for tests only. */
|
|
14
34
|
export declare function resetBranchStatusCache(): void;
|
|
15
35
|
export type BranchHealth = 'clean' | 'dirty' | 'conflict';
|
|
16
36
|
export interface IntegrationBranchStatus {
|
|
@@ -44,13 +64,15 @@ export interface BranchStatusOptions {
|
|
|
44
64
|
branchMonitors?: BranchMonitorEntry[];
|
|
45
65
|
}
|
|
46
66
|
/**
|
|
47
|
-
* Compute branch status for all three tiers.
|
|
67
|
+
* Compute branch status for all three tiers of ONE product.
|
|
48
68
|
*
|
|
49
69
|
* Safe to call from the heartbeat loop: uses short git timeouts
|
|
50
70
|
* and catches all errors so a single failure skips that entry
|
|
51
71
|
* rather than failing the entire heartbeat.
|
|
52
72
|
*
|
|
53
|
-
* @param config -
|
|
73
|
+
* @param config - Product-scoped daemon config (configForProduct); provides
|
|
74
|
+
* productId, repoPath, integrationBranch. Only worktrees owned by
|
|
75
|
+
* config.productId are evaluated, each against its own repoPath.
|
|
54
76
|
* @param options - Optional overrides for mainBranch and branchMonitors from the product record
|
|
55
77
|
*/
|
|
56
78
|
export declare function computeBranchStatus(config: DaemonConfig, options?: BranchStatusOptions): BranchStatusPayload;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"branch-status.d.ts","sourceRoot":"","sources":["../src/branch-status.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"branch-status.d.ts","sourceRoot":"","sources":["../src/branch-status.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAM/C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAsChE,iDAAiD;AACjD,wBAAgB,sBAAsB,IAAI,IAAI,CAG7C;AAID,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,OAAO,GAAG,UAAU,CAAC;AAE1D,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,YAAY,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,YAAY,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,uBAAuB,GAAG,IAAI,CAAC;IAC5C,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,OAAO,EAAE,iBAAiB,EAAE,CAAC;CAC9B;AAED,kDAAkD;AAClD,MAAM,WAAW,mBAAmB;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,kBAAkB,EAAE,CAAC;CACvC;AA6ED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,mBAAmB,CAuM5G"}
|
package/dist/branch-status.js
CHANGED
|
@@ -7,42 +7,67 @@
|
|
|
7
7
|
* 3. Each focus worktree vs integration
|
|
8
8
|
*
|
|
9
9
|
* Results ride in the heartbeat metadata field (no new tables).
|
|
10
|
+
*
|
|
11
|
+
* Multi-product: computeBranchStatus is called once per configured product
|
|
12
|
+
* with a product-scoped config (configForProduct). The focus worktree map
|
|
13
|
+
* spans all products, so this module scopes it by each entry's productId and
|
|
14
|
+
* runs git against the entry's own repoPath — evaluating a worktree against
|
|
15
|
+
* a repository that does not own it is unrepresentable here. All caches are
|
|
16
|
+
* keyed per product so one product's tick cannot evict another's state.
|
|
17
|
+
*
|
|
18
|
+
* Failure semantics (two distinct kinds, deliberately kept apart):
|
|
19
|
+
* - TRANSIENT git failures (lock contention, mid-rebase, timeouts) fall
|
|
20
|
+
* back to the last good cached status without raising anything — this
|
|
21
|
+
* tolerance predates this module split and prevents UI flicker.
|
|
22
|
+
* - PERMANENT failures (unknown revision, not a git repository, bad
|
|
23
|
+
* object) mean the branch we believe exists cannot be resolved where we
|
|
24
|
+
* looked: an attribution error, not contention. These are surfaced via
|
|
25
|
+
* a healthEvent + error log (once per focus per daemon run) instead of
|
|
26
|
+
* silently rendering identically to "no worktree". A worktree entry in
|
|
27
|
+
* the map IS the claim that its branch should exist; a legitimately
|
|
28
|
+
* deleted branch is removed from the map (removeFocusWorktree) before
|
|
29
|
+
* ever being evaluated here, so ordinary deletions raise no events.
|
|
10
30
|
*/
|
|
11
31
|
import { runGitSync } from './git/index.js';
|
|
12
32
|
import { getDefaultBranch } from './git/index.js';
|
|
13
33
|
import { getAllFocusWorktrees } from './focus-worktree-state.js';
|
|
14
34
|
import { getActiveTeams } from './focus-team-state.js';
|
|
35
|
+
import { healthEvents } from './health-events.js';
|
|
36
|
+
import { createLogger } from './log.js';
|
|
37
|
+
const log = createLogger({ module: 'branch-status' });
|
|
15
38
|
/** Short timeout for git commands to avoid blocking the heartbeat. */
|
|
16
39
|
const BRANCH_STATUS_GIT_TIMEOUT_MS = 5_000;
|
|
40
|
+
const cachesByProduct = new Map();
|
|
17
41
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* prevents computing fresh status, avoiding UI flicker.
|
|
21
|
-
*/
|
|
22
|
-
let lastGoodIntegrationStatus = null;
|
|
23
|
-
/**
|
|
24
|
-
* Cache of last successful focus branch status per focus ID.
|
|
25
|
-
* Reused when a transient git failure (lock contention, mid-rebase)
|
|
26
|
-
* prevents computing fresh status, avoiding UI flicker.
|
|
42
|
+
* Focus IDs whose permanent-failure health event has already been emitted
|
|
43
|
+
* this daemon run — one event per focus, not one per heartbeat tick.
|
|
27
44
|
*/
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
45
|
+
const permanentFailureEmitted = new Set();
|
|
46
|
+
function cacheForProduct(key) {
|
|
47
|
+
let cache = cachesByProduct.get(key);
|
|
48
|
+
if (!cache) {
|
|
49
|
+
cache = { integration: null, focus: new Map(), remote: new Map() };
|
|
50
|
+
cachesByProduct.set(key, cache);
|
|
51
|
+
}
|
|
52
|
+
return cache;
|
|
53
|
+
}
|
|
54
|
+
/** Reset all caches. Exported for tests only. */
|
|
35
55
|
export function resetBranchStatusCache() {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
lastGoodRemoteStatus.clear();
|
|
56
|
+
cachesByProduct.clear();
|
|
57
|
+
permanentFailureEmitted.clear();
|
|
39
58
|
}
|
|
40
59
|
// ── Helpers ──────────────────────────────────────────────────────────
|
|
41
60
|
const gitOpts = { timeoutMs: BRANCH_STATUS_GIT_TIMEOUT_MS };
|
|
61
|
+
/**
|
|
62
|
+
* Git stderr patterns that mean the ref/repository itself is unresolvable —
|
|
63
|
+
* a permanent condition no retry will fix, as opposed to contention.
|
|
64
|
+
*/
|
|
65
|
+
const PERMANENT_GIT_FAILURE_RE = /unknown revision|bad revision|ambiguous argument|not a git repository|bad object|invalid ref/i;
|
|
42
66
|
/**
|
|
43
67
|
* Count commits in A that are not in B: `git rev-list --count B..A`.
|
|
44
|
-
* Returns null on
|
|
45
|
-
*
|
|
68
|
+
* Returns a null count on failure, classified as transient (git was busy —
|
|
69
|
+
* fall back to cached data) or permanent (the ref cannot resolve where we
|
|
70
|
+
* looked — an attribution error to surface, not to swallow).
|
|
46
71
|
*
|
|
47
72
|
* @param noMerges - When true, adds `--no-merges` to skip merge commits.
|
|
48
73
|
* Useful for remote monitors where "Merge main into qa" commits are
|
|
@@ -54,24 +79,51 @@ function revListCount(refA, refB, cwd, noMerges) {
|
|
|
54
79
|
args.push('--no-merges');
|
|
55
80
|
args.push(`${refB}..${refA}`);
|
|
56
81
|
const result = runGitSync(args, cwd, gitOpts);
|
|
57
|
-
if (!result.success)
|
|
58
|
-
return
|
|
82
|
+
if (!result.success) {
|
|
83
|
+
return PERMANENT_GIT_FAILURE_RE.test(result.error)
|
|
84
|
+
? { count: null, failure: 'permanent', message: result.error }
|
|
85
|
+
: { count: null, failure: 'transient' };
|
|
86
|
+
}
|
|
59
87
|
const n = parseInt(result.output, 10);
|
|
60
|
-
return Number.isNaN(n) ? null : n;
|
|
88
|
+
return Number.isNaN(n) ? { count: null, failure: 'transient' } : { count: n };
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Surface a permanent branch-resolution failure for a focus: error log plus
|
|
92
|
+
* a healthEvent (rides in heartbeat metadata), emitted once per focus per
|
|
93
|
+
* daemon run. This is the channel that distinguishes "could not determine"
|
|
94
|
+
* from "no worktree" — the payload entry falls back to cache (or is omitted),
|
|
95
|
+
* but the failure is never silent.
|
|
96
|
+
*/
|
|
97
|
+
function surfacePermanentFocusFailure(focusId, branch, repoPath, productId, message) {
|
|
98
|
+
log.error(`Permanent branch-status failure for focus ${focusId}: ` +
|
|
99
|
+
`cannot resolve ${branch} in ${repoPath}: ${message}`);
|
|
100
|
+
if (permanentFailureEmitted.has(focusId))
|
|
101
|
+
return;
|
|
102
|
+
permanentFailureEmitted.add(focusId);
|
|
103
|
+
healthEvents.emit({
|
|
104
|
+
severity: 'warn',
|
|
105
|
+
source: 'branch-status',
|
|
106
|
+
code: 'branch_status.attribution_error',
|
|
107
|
+
message: `Branch ${branch} for focus ${focusId} cannot be resolved in ${repoPath}: ${message}`,
|
|
108
|
+
productId,
|
|
109
|
+
});
|
|
61
110
|
}
|
|
62
111
|
// ── Main ─────────────────────────────────────────────────────────────
|
|
63
112
|
/**
|
|
64
|
-
* Compute branch status for all three tiers.
|
|
113
|
+
* Compute branch status for all three tiers of ONE product.
|
|
65
114
|
*
|
|
66
115
|
* Safe to call from the heartbeat loop: uses short git timeouts
|
|
67
116
|
* and catches all errors so a single failure skips that entry
|
|
68
117
|
* rather than failing the entire heartbeat.
|
|
69
118
|
*
|
|
70
|
-
* @param config -
|
|
119
|
+
* @param config - Product-scoped daemon config (configForProduct); provides
|
|
120
|
+
* productId, repoPath, integrationBranch. Only worktrees owned by
|
|
121
|
+
* config.productId are evaluated, each against its own repoPath.
|
|
71
122
|
* @param options - Optional overrides for mainBranch and branchMonitors from the product record
|
|
72
123
|
*/
|
|
73
124
|
export function computeBranchStatus(config, options) {
|
|
74
|
-
const { repoPath, integrationBranch } = config;
|
|
125
|
+
const { repoPath, integrationBranch, productId } = config;
|
|
126
|
+
const cache = cacheForProduct(productId || repoPath);
|
|
75
127
|
const mainBranch = options?.mainBranch || getDefaultBranch(repoPath);
|
|
76
128
|
const monitors = options?.branchMonitors?.length
|
|
77
129
|
? options.branchMonitors
|
|
@@ -86,31 +138,31 @@ export function computeBranchStatus(config, options) {
|
|
|
86
138
|
// not new code. Without this, integration perpetually shows as "ahead".
|
|
87
139
|
const aheadOfMain = revListCount(integrationBranch, mainBranch, repoPath, true);
|
|
88
140
|
const behindMain = revListCount(mainBranch, integrationBranch, repoPath);
|
|
89
|
-
if (aheadOfMain === null || behindMain === null) {
|
|
141
|
+
if (aheadOfMain.count === null || behindMain.count === null) {
|
|
90
142
|
// Transient git failure (lock contention, mid-rebase) — use cached status
|
|
91
|
-
integration =
|
|
143
|
+
integration = cache.integration;
|
|
92
144
|
}
|
|
93
145
|
else {
|
|
94
146
|
let health = 'clean';
|
|
95
|
-
if (aheadOfMain > 0 && behindMain > 0) {
|
|
147
|
+
if (aheadOfMain.count > 0 && behindMain.count > 0) {
|
|
96
148
|
health = 'conflict'; // truly diverged — both directions have commits
|
|
97
149
|
}
|
|
98
|
-
else if (aheadOfMain > 0 || behindMain > 0) {
|
|
150
|
+
else if (aheadOfMain.count > 0 || behindMain.count > 0) {
|
|
99
151
|
health = 'dirty';
|
|
100
152
|
}
|
|
101
153
|
integration = {
|
|
102
154
|
branch: integrationBranch,
|
|
103
155
|
health,
|
|
104
|
-
aheadOfMain,
|
|
105
|
-
behindMain,
|
|
156
|
+
aheadOfMain: aheadOfMain.count,
|
|
157
|
+
behindMain: behindMain.count,
|
|
106
158
|
};
|
|
107
|
-
|
|
159
|
+
cache.integration = integration;
|
|
108
160
|
}
|
|
109
161
|
}
|
|
110
162
|
}
|
|
111
163
|
catch {
|
|
112
164
|
// Non-fatal: use cached integration status if available
|
|
113
|
-
integration =
|
|
165
|
+
integration = cache.integration;
|
|
114
166
|
}
|
|
115
167
|
// ── Remote branch monitors ──────────────────────────────────────
|
|
116
168
|
const remotes = [];
|
|
@@ -123,61 +175,78 @@ export function computeBranchStatus(config, options) {
|
|
|
123
175
|
const aheadOfMain = revListCount(monitor.ref, mainBranch, repoPath, true);
|
|
124
176
|
// behindMain: commits in main not in remote (remote is behind)
|
|
125
177
|
const behindMain = revListCount(mainBranch, monitor.ref, repoPath);
|
|
126
|
-
if (aheadOfMain === null || behindMain === null) {
|
|
178
|
+
if (aheadOfMain.count === null || behindMain.count === null) {
|
|
127
179
|
// Transient git failure — use cached status
|
|
128
|
-
const cached =
|
|
180
|
+
const cached = cache.remote.get(monitor.ref);
|
|
129
181
|
remotes.push(cached ?? { ref: monitor.ref, label: monitor.label, aheadOfMain: null, behindMain: null });
|
|
130
182
|
}
|
|
131
183
|
else {
|
|
132
184
|
const entry = {
|
|
133
185
|
ref: monitor.ref,
|
|
134
186
|
label: monitor.label,
|
|
135
|
-
aheadOfMain,
|
|
136
|
-
behindMain,
|
|
187
|
+
aheadOfMain: aheadOfMain.count,
|
|
188
|
+
behindMain: behindMain.count,
|
|
137
189
|
};
|
|
138
|
-
|
|
190
|
+
cache.remote.set(monitor.ref, entry);
|
|
139
191
|
remotes.push(entry);
|
|
140
192
|
}
|
|
141
193
|
}
|
|
142
194
|
else {
|
|
143
195
|
// Ref doesn't exist — use cached if available, otherwise emit grey sentinel
|
|
144
|
-
const cached =
|
|
196
|
+
const cached = cache.remote.get(monitor.ref);
|
|
145
197
|
remotes.push(cached ?? { ref: monitor.ref, label: monitor.label, aheadOfMain: null, behindMain: null });
|
|
146
198
|
}
|
|
147
199
|
}
|
|
148
200
|
catch {
|
|
149
201
|
// Non-fatal: use cached status if available, otherwise emit grey sentinel
|
|
150
|
-
const cached =
|
|
202
|
+
const cached = cache.remote.get(monitor.ref);
|
|
151
203
|
remotes.push(cached ?? { ref: monitor.ref, label: monitor.label, aheadOfMain: null, behindMain: null });
|
|
152
204
|
}
|
|
153
205
|
}
|
|
154
206
|
// Evict remote cache entries for monitors no longer configured
|
|
155
207
|
const monitorRefs = new Set(monitors.map(m => m.ref));
|
|
156
|
-
for (const cachedRef of
|
|
208
|
+
for (const cachedRef of cache.remote.keys()) {
|
|
157
209
|
if (!monitorRefs.has(cachedRef)) {
|
|
158
|
-
|
|
210
|
+
cache.remote.delete(cachedRef);
|
|
159
211
|
}
|
|
160
212
|
}
|
|
161
213
|
// ── Focus worktree statuses ───────────────────────────────────
|
|
162
214
|
const focuses = [];
|
|
163
215
|
const worktrees = getAllFocusWorktrees();
|
|
164
216
|
const teams = getActiveTeams();
|
|
217
|
+
const ownFocusIds = new Set();
|
|
165
218
|
for (const [focusId, info] of worktrees) {
|
|
219
|
+
// The worktree map is cross-product; only evaluate worktrees this
|
|
220
|
+
// product owns, and evaluate them against the entry's OWN repo.
|
|
221
|
+
if (info.productId !== productId)
|
|
222
|
+
continue;
|
|
223
|
+
ownFocusIds.add(focusId);
|
|
224
|
+
const focusRepoPath = info.repoPath || repoPath;
|
|
166
225
|
try {
|
|
167
226
|
const headResult = runGitSync(['rev-parse', 'HEAD'], info.worktreePath, gitOpts);
|
|
168
227
|
if (!headResult.success) {
|
|
169
228
|
// Transient failure — use cached status if available
|
|
170
|
-
const cached =
|
|
229
|
+
const cached = cache.focus.get(focusId);
|
|
171
230
|
if (cached)
|
|
172
231
|
focuses.push(cached);
|
|
173
232
|
continue;
|
|
174
233
|
}
|
|
175
234
|
const headSha = headResult.output;
|
|
176
|
-
const aheadOfIntegration = revListCount(info.branchName, integrationBranch,
|
|
177
|
-
const behindIntegration = revListCount(integrationBranch, info.branchName,
|
|
178
|
-
if (aheadOfIntegration === null || behindIntegration === null) {
|
|
179
|
-
|
|
180
|
-
|
|
235
|
+
const aheadOfIntegration = revListCount(info.branchName, integrationBranch, focusRepoPath, true);
|
|
236
|
+
const behindIntegration = revListCount(integrationBranch, info.branchName, focusRepoPath);
|
|
237
|
+
if (aheadOfIntegration.count === null || behindIntegration.count === null) {
|
|
238
|
+
const permanent = aheadOfIntegration.failure === 'permanent' ? aheadOfIntegration :
|
|
239
|
+
behindIntegration.failure === 'permanent' ? behindIntegration :
|
|
240
|
+
null;
|
|
241
|
+
if (permanent) {
|
|
242
|
+
// The branch this worktree entry claims exists cannot be resolved
|
|
243
|
+
// in its own repository: an attribution error, not contention.
|
|
244
|
+
surfacePermanentFocusFailure(focusId, info.branchName, focusRepoPath, productId, permanent.message ?? 'unknown git error');
|
|
245
|
+
}
|
|
246
|
+
// Either way, fall back to cached status (transient tolerance for
|
|
247
|
+
// contention; last-known-good rather than a wrong fresh value for
|
|
248
|
+
// permanent failures — the healthEvent above carries the error).
|
|
249
|
+
const cached = cache.focus.get(focusId);
|
|
181
250
|
if (cached)
|
|
182
251
|
focuses.push(cached);
|
|
183
252
|
continue;
|
|
@@ -189,7 +258,7 @@ export function computeBranchStatus(config, options) {
|
|
|
189
258
|
if (isConflicting) {
|
|
190
259
|
health = 'conflict';
|
|
191
260
|
}
|
|
192
|
-
else if (aheadOfIntegration > 0) {
|
|
261
|
+
else if (aheadOfIntegration.count > 0) {
|
|
193
262
|
health = 'dirty';
|
|
194
263
|
}
|
|
195
264
|
const entry = {
|
|
@@ -197,23 +266,25 @@ export function computeBranchStatus(config, options) {
|
|
|
197
266
|
branch: info.branchName,
|
|
198
267
|
headSha,
|
|
199
268
|
health,
|
|
200
|
-
aheadOfIntegration,
|
|
201
|
-
behindIntegration,
|
|
269
|
+
aheadOfIntegration: aheadOfIntegration.count,
|
|
270
|
+
behindIntegration: behindIntegration.count,
|
|
202
271
|
};
|
|
203
|
-
|
|
272
|
+
cache.focus.set(focusId, entry);
|
|
204
273
|
focuses.push(entry);
|
|
205
274
|
}
|
|
206
275
|
catch {
|
|
207
276
|
// Transient failure — use cached status if available
|
|
208
|
-
const cached =
|
|
277
|
+
const cached = cache.focus.get(focusId);
|
|
209
278
|
if (cached)
|
|
210
279
|
focuses.push(cached);
|
|
211
280
|
}
|
|
212
281
|
}
|
|
213
|
-
// Evict cache entries for worktrees that no longer exist
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
282
|
+
// Evict cache entries for THIS product's worktrees that no longer exist.
|
|
283
|
+
// (Other products' focuses never enter this cache — it is per-product.)
|
|
284
|
+
for (const cachedId of cache.focus.keys()) {
|
|
285
|
+
if (!ownFocusIds.has(cachedId)) {
|
|
286
|
+
cache.focus.delete(cachedId);
|
|
287
|
+
permanentFailureEmitted.delete(cachedId);
|
|
217
288
|
}
|
|
218
289
|
}
|
|
219
290
|
return { integration, remotes, focuses };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"branch-status.js","sourceRoot":"","sources":["../src/branch-status.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"branch-status.js","sourceRoot":"","sources":["../src/branch-status.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,MAAM,GAAG,GAAG,YAAY,CAAC,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC,CAAC;AAEtD,sEAAsE;AACtE,MAAM,4BAA4B,GAAG,KAAK,CAAC;AAe3C,MAAM,eAAe,GAAG,IAAI,GAAG,EAA8B,CAAC;AAE9D;;;GAGG;AACH,MAAM,uBAAuB,GAAG,IAAI,GAAG,EAAU,CAAC;AAElD,SAAS,eAAe,CAAC,GAAW;IAClC,IAAI,KAAK,GAAG,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACrC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,KAAK,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC;QACnE,eAAe,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,sBAAsB;IACpC,eAAe,CAAC,KAAK,EAAE,CAAC;IACxB,uBAAuB,CAAC,KAAK,EAAE,CAAC;AAClC,CAAC;AAyCD,wEAAwE;AAExE,MAAM,OAAO,GAAG,EAAE,SAAS,EAAE,4BAA4B,EAAE,CAAC;AAE5D;;;GAGG;AACH,MAAM,wBAAwB,GAC5B,+FAA+F,CAAC;AAUlG;;;;;;;;;GASG;AACH,SAAS,YAAY,CAAC,IAAY,EAAE,IAAY,EAAE,GAAW,EAAE,QAAkB;IAC/E,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IACrC,IAAI,QAAQ;QAAE,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACvC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,KAAK,IAAI,EAAE,CAAC,CAAC;IAC9B,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;IAC9C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,wBAAwB,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;YAChD,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,EAAE;YAC9D,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;IAC5C,CAAC;IACD,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACtC,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;AAChF,CAAC;AAED;;;;;;GAMG;AACH,SAAS,4BAA4B,CACnC,OAAe,EACf,MAAc,EACd,QAAgB,EAChB,SAAiB,EACjB,OAAe;IAEf,GAAG,CAAC,KAAK,CACP,6CAA6C,OAAO,IAAI;QACxD,kBAAkB,MAAM,OAAO,QAAQ,KAAK,OAAO,EAAE,CACtD,CAAC;IACF,IAAI,uBAAuB,CAAC,GAAG,CAAC,OAAO,CAAC;QAAE,OAAO;IACjD,uBAAuB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACrC,YAAY,CAAC,IAAI,CAAC;QAChB,QAAQ,EAAE,MAAM;QAChB,MAAM,EAAE,eAAe;QACvB,IAAI,EAAE,iCAAiC;QACvC,OAAO,EACL,UAAU,MAAM,cAAc,OAAO,0BAA0B,QAAQ,KAAK,OAAO,EAAE;QACvF,SAAS;KACV,CAAC,CAAC;AACL,CAAC;AAED,wEAAwE;AAExE;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAoB,EAAE,OAA6B;IACrF,MAAM,EAAE,QAAQ,EAAE,iBAAiB,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC;IAC1D,MAAM,KAAK,GAAG,eAAe,CAAC,SAAS,IAAI,QAAQ,CAAC,CAAC;IACrD,MAAM,UAAU,GAAG,OAAO,EAAE,UAAU,IAAI,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IACrE,MAAM,QAAQ,GAAG,OAAO,EAAE,cAAc,EAAE,MAAM;QAC9C,CAAC,CAAC,OAAO,CAAC,cAAc;QACxB,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,UAAU,UAAU,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;IAElD,oEAAoE;IACpE,IAAI,WAAW,GAAmC,IAAI,CAAC;IACvD,IAAI,CAAC;QACH,+CAA+C;QAC/C,MAAM,QAAQ,GAAG,UAAU,CACzB,CAAC,WAAW,EAAE,UAAU,EAAE,iBAAiB,CAAC,EAC5C,QAAQ,EACR,OAAO,CACR,CAAC;QACF,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;YACrB,yEAAyE;YACzE,wEAAwE;YACxE,MAAM,WAAW,GAAG,YAAY,CAAC,iBAAiB,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAChF,MAAM,UAAU,GAAG,YAAY,CAAC,UAAU,EAAE,iBAAiB,EAAE,QAAQ,CAAC,CAAC;YAEzE,IAAI,WAAW,CAAC,KAAK,KAAK,IAAI,IAAI,UAAU,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;gBAC5D,0EAA0E;gBAC1E,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;YAClC,CAAC;iBAAM,CAAC;gBACN,IAAI,MAAM,GAAiB,OAAO,CAAC;gBACnC,IAAI,WAAW,CAAC,KAAK,GAAG,CAAC,IAAI,UAAU,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC;oBAClD,MAAM,GAAG,UAAU,CAAC,CAAC,gDAAgD;gBACvE,CAAC;qBAAM,IAAI,WAAW,CAAC,KAAK,GAAG,CAAC,IAAI,UAAU,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC;oBACzD,MAAM,GAAG,OAAO,CAAC;gBACnB,CAAC;gBAED,WAAW,GAAG;oBACZ,MAAM,EAAE,iBAAiB;oBACzB,MAAM;oBACN,WAAW,EAAE,WAAW,CAAC,KAAK;oBAC9B,UAAU,EAAE,UAAU,CAAC,KAAK;iBAC7B,CAAC;gBACF,KAAK,CAAC,WAAW,GAAG,WAAW,CAAC;YAClC,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,wDAAwD;QACxD,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;IAClC,CAAC;IAED,mEAAmE;IACnE,MAAM,OAAO,GAAyB,EAAE,CAAC;IACzC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,UAAU,CACzB,CAAC,WAAW,EAAE,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,EACtC,QAAQ,EACR,OAAO,CACR,CAAC;YACF,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;gBACrB,0EAA0E;gBAC1E,+EAA+E;gBAC/E,MAAM,WAAW,GAAG,YAAY,CAAC,OAAO,CAAC,GAAG,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;gBAC1E,+DAA+D;gBAC/D,MAAM,UAAU,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;gBAEnE,IAAI,WAAW,CAAC,KAAK,KAAK,IAAI,IAAI,UAAU,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;oBAC5D,4CAA4C;oBAC5C,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;oBAC7C,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC1G,CAAC;qBAAM,CAAC;oBACN,MAAM,KAAK,GAAuB;wBAChC,GAAG,EAAE,OAAO,CAAC,GAAG;wBAChB,KAAK,EAAE,OAAO,CAAC,KAAK;wBACpB,WAAW,EAAE,WAAW,CAAC,KAAK;wBAC9B,UAAU,EAAE,UAAU,CAAC,KAAK;qBAC7B,CAAC;oBACF,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;oBACrC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACtB,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,4EAA4E;gBAC5E,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBAC7C,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;YAC1G,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,0EAA0E;YAC1E,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAC7C,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1G,CAAC;IACH,CAAC;IAED,+DAA+D;IAC/D,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACtD,KAAK,MAAM,SAAS,IAAI,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QAC5C,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YAChC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAED,iEAAiE;IACjE,MAAM,OAAO,GAAwB,EAAE,CAAC;IACxC,MAAM,SAAS,GAAG,oBAAoB,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,cAAc,EAAE,CAAC;IAC/B,MAAM,WAAW,GAAG,IAAI,GAAG,EAAU,CAAC;IAEtC,KAAK,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,SAAS,EAAE,CAAC;QACxC,kEAAkE;QAClE,gEAAgE;QAChE,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS;YAAE,SAAS;QAC3C,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACzB,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC;QAEhD,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,UAAU,CAC3B,CAAC,WAAW,EAAE,MAAM,CAAC,EACrB,IAAI,CAAC,YAAY,EACjB,OAAO,CACR,CAAC;YACF,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;gBACxB,qDAAqD;gBACrD,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBACxC,IAAI,MAAM;oBAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACjC,SAAS;YACX,CAAC;YACD,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC;YAElC,MAAM,kBAAkB,GAAG,YAAY,CACrC,IAAI,CAAC,UAAU,EACf,iBAAiB,EACjB,aAAa,EACb,IAAI,CACL,CAAC;YACF,MAAM,iBAAiB,GAAG,YAAY,CACpC,iBAAiB,EACjB,IAAI,CAAC,UAAU,EACf,aAAa,CACd,CAAC;YAEF,IAAI,kBAAkB,CAAC,KAAK,KAAK,IAAI,IAAI,iBAAiB,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;gBAC1E,MAAM,SAAS,GACb,kBAAkB,CAAC,OAAO,KAAK,WAAW,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC;oBACjE,iBAAiB,CAAC,OAAO,KAAK,WAAW,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC;wBAC/D,IAAI,CAAC;gBACP,IAAI,SAAS,EAAE,CAAC;oBACd,kEAAkE;oBAClE,+DAA+D;oBAC/D,4BAA4B,CAC1B,OAAO,EACP,IAAI,CAAC,UAAU,EACf,aAAa,EACb,SAAS,EACT,SAAS,CAAC,OAAO,IAAI,mBAAmB,CACzC,CAAC;gBACJ,CAAC;gBACD,kEAAkE;gBAClE,kEAAkE;gBAClE,iEAAiE;gBACjE,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBACxC,IAAI,MAAM;oBAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACjC,SAAS;YACX,CAAC;YAED,mDAAmD;YACnD,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAChC,MAAM,aAAa,GAAG,IAAI,EAAE,sBAAsB,KAAK,IAAI,CAAC;YAE5D,IAAI,MAAM,GAAiB,OAAO,CAAC;YACnC,IAAI,aAAa,EAAE,CAAC;gBAClB,MAAM,GAAG,UAAU,CAAC;YACtB,CAAC;iBAAM,IAAI,kBAAkB,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC;gBACxC,MAAM,GAAG,OAAO,CAAC;YACnB,CAAC;YAED,MAAM,KAAK,GAAsB;gBAC/B,OAAO;gBACP,MAAM,EAAE,IAAI,CAAC,UAAU;gBACvB,OAAO;gBACP,MAAM;gBACN,kBAAkB,EAAE,kBAAkB,CAAC,KAAK;gBAC5C,iBAAiB,EAAE,iBAAiB,CAAC,KAAK;aAC3C,CAAC;YACF,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YAChC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;QAAC,MAAM,CAAC;YACP,qDAAqD;YACrD,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACxC,IAAI,MAAM;gBAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;IAED,yEAAyE;IACzE,wEAAwE;IACxE,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QAC1C,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC/B,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC7B,uBAAuB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAC3C,CAAC"}
|
|
@@ -12,10 +12,16 @@
|
|
|
12
12
|
* and terminate
|
|
13
13
|
* 2. team has NO actionable work -> terminate cleanly (daemon/review-
|
|
14
14
|
* managed states move the remaining deliveries)
|
|
15
|
-
* 3.
|
|
16
|
-
*
|
|
15
|
+
* 3. team is blocked on an unanswered DIRECTED escalation (needs_intent /
|
|
16
|
+
* needs_clarification) anchored to a delivery it is working -> hold: do
|
|
17
|
+
* NOT escalate, do NOT re-engage. It is waiting on a human, not stalling.
|
|
18
|
+
* This precedes the no-progress and handoff/re-engage branches so a
|
|
19
|
+
* blocked team is never counted as a stall (its own park is the signal a
|
|
20
|
+
* human already sees).
|
|
21
|
+
* 4. no-progress counter crossed the limit -> escalate and terminate
|
|
22
|
+
* 5. actionable deliveries carry open issues -> mid-focus handoff with
|
|
17
23
|
* the new work
|
|
18
|
-
*
|
|
24
|
+
* 6. otherwise (planning deliveries remain) -> re-engagement nudge
|
|
19
25
|
*/
|
|
20
26
|
/** Facts the decision is made from. All computed post-self-heal-advance. */
|
|
21
27
|
export interface CompletionDecisionFacts {
|
|
@@ -45,6 +51,16 @@ export interface CompletionDecisionFacts {
|
|
|
45
51
|
noProgressLimit: number;
|
|
46
52
|
/** At least one agent-actionable delivery carries an open issue. */
|
|
47
53
|
hasActionableOpenIssues: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* An agent-actionable delivery the team is working carries an OPEN, unanswered
|
|
56
|
+
* DIRECTED escalation (disposition needs_intent / needs_clarification). The
|
|
57
|
+
* team is blocked on a human answer, not stalling. Computed fail-OPEN: a
|
|
58
|
+
* lookup error resolves to false, so a genuine stall is never masked by a
|
|
59
|
+
* failed check. Only consulted on the teamHasActionableWork path (a team with
|
|
60
|
+
* nothing to do is handled by the terminate branches above, where a block is
|
|
61
|
+
* moot).
|
|
62
|
+
*/
|
|
63
|
+
blockedOnDirectedEscalation: boolean;
|
|
48
64
|
}
|
|
49
65
|
/** The action handleCompletionEvent executes for this cycle. */
|
|
50
66
|
export type CompletionAction =
|
|
@@ -67,6 +83,16 @@ export type CompletionAction =
|
|
|
67
83
|
/** Planning deliveries remain: send a re-engagement nudge to scope them. */
|
|
68
84
|
| {
|
|
69
85
|
kind: 'reengage';
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Team is blocked on an unanswered directed escalation: hold in place. No
|
|
89
|
+
* escalation filed, no wake message sent, no termination -- the open question
|
|
90
|
+
* is the single signal a human needs, and re-engaging would only burn model
|
|
91
|
+
* spend rediscovering it. The team resumes when the escalation is answered
|
|
92
|
+
* (the answer read-back path re-engages it).
|
|
93
|
+
*/
|
|
94
|
+
| {
|
|
95
|
+
kind: 'hold_blocked_on_directed_escalation';
|
|
70
96
|
};
|
|
71
97
|
/**
|
|
72
98
|
* Whether the (async, workflow-fetching) non-advanceability lookup should run
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"completion-decision.d.ts","sourceRoot":"","sources":["../../src/completion/completion-decision.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"completion-decision.d.ts","sourceRoot":"","sources":["../../src/completion/completion-decision.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,4EAA4E;AAC5E,MAAM,WAAW,uBAAuB;IACtC;;;;OAIG;IACH,qBAAqB,EAAE,OAAO,CAAC;IAC/B;;;;;OAKG;IACH,iBAAiB,EAAE,OAAO,CAAC;IAC3B;;;;;OAKG;IACH,sBAAsB,EAAE,OAAO,CAAC;IAChC,wEAAwE;IACxE,gBAAgB,EAAE,MAAM,CAAC;IACzB,yEAAyE;IACzE,eAAe,EAAE,MAAM,CAAC;IACxB,oEAAoE;IACpE,uBAAuB,EAAE,OAAO,CAAC;IACjC;;;;;;;;OAQG;IACH,2BAA2B,EAAE,OAAO,CAAC;CACtC;AAED,gEAAgE;AAChE,MAAM,MAAM,gBAAgB;AAC1B,6EAA6E;AAC3E;IAAE,IAAI,EAAE,wCAAwC,CAAA;CAAE;AACpD,0EAA0E;GACxE;IAAE,IAAI,EAAE,8BAA8B,CAAA;CAAE;AAC1C,0EAA0E;GACxE;IAAE,IAAI,EAAE,oCAAoC,CAAA;CAAE;AAChD,qEAAqE;GACnE;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE;AAC9B,4EAA4E;GAC1E;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE;AACtB;;;;;;GAMG;GACD;IAAE,IAAI,EAAE,qCAAqC,CAAA;CAAE,CAAC;AAEpD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,IAAI,CAAC,uBAAuB,EAAE,uBAAuB,GAAG,mBAAmB,CAAC,GAClF,OAAO,CAET;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,uBAAuB,GAAG,gBAAgB,CAoBvF"}
|
|
@@ -12,10 +12,16 @@
|
|
|
12
12
|
* and terminate
|
|
13
13
|
* 2. team has NO actionable work -> terminate cleanly (daemon/review-
|
|
14
14
|
* managed states move the remaining deliveries)
|
|
15
|
-
* 3.
|
|
16
|
-
*
|
|
15
|
+
* 3. team is blocked on an unanswered DIRECTED escalation (needs_intent /
|
|
16
|
+
* needs_clarification) anchored to a delivery it is working -> hold: do
|
|
17
|
+
* NOT escalate, do NOT re-engage. It is waiting on a human, not stalling.
|
|
18
|
+
* This precedes the no-progress and handoff/re-engage branches so a
|
|
19
|
+
* blocked team is never counted as a stall (its own park is the signal a
|
|
20
|
+
* human already sees).
|
|
21
|
+
* 4. no-progress counter crossed the limit -> escalate and terminate
|
|
22
|
+
* 5. actionable deliveries carry open issues -> mid-focus handoff with
|
|
17
23
|
* the new work
|
|
18
|
-
*
|
|
24
|
+
* 6. otherwise (planning deliveries remain) -> re-engagement nudge
|
|
19
25
|
*/
|
|
20
26
|
/**
|
|
21
27
|
* Whether the (async, workflow-fetching) non-advanceability lookup should run
|
|
@@ -37,6 +43,12 @@ export function decideCompletionAction(facts) {
|
|
|
37
43
|
}
|
|
38
44
|
return { kind: 'terminate_no_actionable_work' };
|
|
39
45
|
}
|
|
46
|
+
// A team parked on its own unanswered directed escalation is blocked, not
|
|
47
|
+
// stalled: hold ahead of the no-progress and handoff/re-engage branches so it
|
|
48
|
+
// is neither escalated nor re-engaged while the question is open.
|
|
49
|
+
if (facts.blockedOnDirectedEscalation) {
|
|
50
|
+
return { kind: 'hold_blocked_on_directed_escalation' };
|
|
51
|
+
}
|
|
40
52
|
if (facts.noProgressCycles >= facts.noProgressLimit) {
|
|
41
53
|
return { kind: 'escalate_no_progress_and_terminate' };
|
|
42
54
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"completion-decision.js","sourceRoot":"","sources":["../../src/completion/completion-decision.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"completion-decision.js","sourceRoot":"","sources":["../../src/completion/completion-decision.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AA+DH;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB,CACvC,KAAmF;IAEnF,OAAO,CAAC,KAAK,CAAC,qBAAqB,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC;AAClE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,KAA8B;IACnE,IAAI,CAAC,KAAK,CAAC,qBAAqB,EAAE,CAAC;QACjC,IAAI,CAAC,KAAK,CAAC,iBAAiB,IAAI,KAAK,CAAC,sBAAsB,EAAE,CAAC;YAC7D,OAAO,EAAE,IAAI,EAAE,wCAAwC,EAAE,CAAC;QAC5D,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,8BAA8B,EAAE,CAAC;IAClD,CAAC;IACD,0EAA0E;IAC1E,8EAA8E;IAC9E,kEAAkE;IAClE,IAAI,KAAK,CAAC,2BAA2B,EAAE,CAAC;QACtC,OAAO,EAAE,IAAI,EAAE,qCAAqC,EAAE,CAAC;IACzD,CAAC;IACD,IAAI,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,eAAe,EAAE,CAAC;QACpD,OAAO,EAAE,IAAI,EAAE,oCAAoC,EAAE,CAAC;IACxD,CAAC;IACD,IAAI,KAAK,CAAC,uBAAuB,EAAE,CAAC;QAClC,OAAO,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC;IACtC,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;AAC9B,CAAC"}
|