github-issue-tower-defence-management 1.140.0 → 1.140.2
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/.github/workflows/umino-project.yml +2 -1
- package/CHANGELOG.md +14 -0
- package/README.md +1 -1
- package/bin/adapter/repositories/FileSystemSessionOutputActivityRepository.js +6 -40
- package/bin/adapter/repositories/FileSystemSessionOutputActivityRepository.js.map +1 -1
- package/bin/domain/usecases/NotifySilentLiveSessionsUseCase.js +29 -51
- package/bin/domain/usecases/NotifySilentLiveSessionsUseCase.js.map +1 -1
- package/package.json +1 -1
- package/src/adapter/entry-points/handlers/notifySilentTmuxSessions.test.ts +33 -3
- package/src/adapter/repositories/FileSystemSessionOutputActivityRepository.test.ts +24 -11
- package/src/adapter/repositories/FileSystemSessionOutputActivityRepository.ts +8 -50
- package/src/domain/entities/LiveSessionActivitySnapshot.ts +0 -1
- package/src/domain/entities/LiveSessionOutputActivity.ts +0 -1
- package/src/domain/usecases/NotifySilentLiveSessionsUseCase.test.ts +127 -122
- package/src/domain/usecases/NotifySilentLiveSessionsUseCase.ts +33 -62
- package/types/adapter/repositories/FileSystemSessionOutputActivityRepository.d.ts +1 -1
- package/types/adapter/repositories/FileSystemSessionOutputActivityRepository.d.ts.map +1 -1
- package/types/domain/entities/LiveSessionActivitySnapshot.d.ts +0 -1
- package/types/domain/entities/LiveSessionActivitySnapshot.d.ts.map +1 -1
- package/types/domain/entities/LiveSessionOutputActivity.d.ts +0 -1
- package/types/domain/entities/LiveSessionOutputActivity.d.ts.map +1 -1
- package/types/domain/usecases/NotifySilentLiveSessionsUseCase.d.ts +0 -1
- package/types/domain/usecases/NotifySilentLiveSessionsUseCase.d.ts.map +1 -1
|
@@ -26,15 +26,6 @@ export const DEFAULT_SUBAGENT_RUNNING_THRESHOLD_SECONDS = 15 * 60;
|
|
|
26
26
|
export const DEFAULT_NOTIFICATION_STAGGER_SECONDS = 25;
|
|
27
27
|
export const DEFAULT_CANDIDATE_DEBOUNCE_RECENCY_WINDOW_SECONDS = 15 * 60;
|
|
28
28
|
export const DEFAULT_HUB_TASK_STATUS_CACHE_TTL_SECONDS = 5 * 60;
|
|
29
|
-
// Upper bound on how long an in-progress tool call suppresses the main-stall
|
|
30
|
-
// reminder. Set to 2 hours: comfortably above the ~1-hour maximum duration of
|
|
31
|
-
// the longest legitimate single tool call (the Monitor tool's own timeout
|
|
32
|
-
// ceiling), so every legitimate long-running tool call is still suppressed,
|
|
33
|
-
// while a session whose transcript tail has been an unanswered tool_use for
|
|
34
|
-
// longer than this — for example because the tool call itself hung and never
|
|
35
|
-
// returned — still receives the stall reminder instead of being suppressed
|
|
36
|
-
// forever.
|
|
37
|
-
export const IN_PROGRESS_TOOL_CALL_MAX_SUPPRESS_SECONDS = 2 * 60 * 60;
|
|
38
29
|
|
|
39
30
|
const GITHUB_ISSUE_OR_PULL_URL_PATTERN =
|
|
40
31
|
/^https:\/\/github\.com\/([^/]+)\/([^/]+)\/(?:issues|pull)\/(\d+)$/;
|
|
@@ -71,7 +62,6 @@ type NotifyCandidate = {
|
|
|
71
62
|
sessionName: string;
|
|
72
63
|
message: string;
|
|
73
64
|
sectionLabels: string[];
|
|
74
|
-
mainInputBusy: boolean;
|
|
75
65
|
};
|
|
76
66
|
|
|
77
67
|
export class NotifySilentLiveSessionsUseCase {
|
|
@@ -109,20 +99,36 @@ export class NotifySilentLiveSessionsUseCase {
|
|
|
109
99
|
await this.liveSessionProcessSnapshotProvider.getSnapshot();
|
|
110
100
|
const allInteractiveSessions =
|
|
111
101
|
this.resolveInteractiveLiveSessions.resolve(snapshot);
|
|
112
|
-
|
|
113
|
-
|
|
102
|
+
// Resolve the on-disk Claude transcript for every interactive session
|
|
103
|
+
// before any name-based narrowing. A resolvable transcript is the proof
|
|
104
|
+
// that a session is a live Claude agent session (its transcript, keyed by
|
|
105
|
+
// the session id, is actively present on disk), independent of how the tmux
|
|
106
|
+
// session is named.
|
|
107
|
+
const transcriptPathBySessionName =
|
|
108
|
+
this.interactiveLiveSessionTranscriptResolver.resolveTranscriptPaths(
|
|
109
|
+
allInteractiveSessions,
|
|
110
|
+
);
|
|
111
|
+
// Monitor a session when it is either named after a github.com issue or
|
|
112
|
+
// pull-request URL (the hub-task sessions) or has a resolvable Claude agent
|
|
113
|
+
// transcript (role-named resident leader / PM agent sessions such as app,
|
|
114
|
+
// tdpm-cli, secretary, and the per-project *pm sessions). Gating the
|
|
115
|
+
// broadened inclusion on the resolvable transcript rather than on merely
|
|
116
|
+
// being a tmux session keeps the fail-direction safe: a genuine non-agent
|
|
117
|
+
// interactive session — a login shell, or a viewer such as sso_login or a
|
|
118
|
+
// tdpm viewer — exposes no Claude transcript on disk, so it is still
|
|
119
|
+
// excluded and never reminded.
|
|
120
|
+
const interactiveSessions = allInteractiveSessions.filter(
|
|
121
|
+
(session) =>
|
|
122
|
+
isGitHubIssueOrPullRequestSessionName(session.sessionName) ||
|
|
123
|
+
transcriptPathBySessionName.has(session.sessionName),
|
|
114
124
|
);
|
|
115
|
-
const
|
|
125
|
+
const skippedNonAgentSessionCount =
|
|
116
126
|
allInteractiveSessions.length - interactiveSessions.length;
|
|
117
|
-
if (
|
|
127
|
+
if (skippedNonAgentSessionCount > 0) {
|
|
118
128
|
console.log(
|
|
119
|
-
`Silent live session notification: ignoring ${
|
|
129
|
+
`Silent live session notification: ignoring ${skippedNonAgentSessionCount} interactive session(s) that are neither named after a github.com issue or pull-request URL nor have a resolvable Claude agent transcript.`,
|
|
120
130
|
);
|
|
121
131
|
}
|
|
122
|
-
const transcriptPathBySessionName =
|
|
123
|
-
this.interactiveLiveSessionTranscriptResolver.resolveTranscriptPaths(
|
|
124
|
-
interactiveSessions,
|
|
125
|
-
);
|
|
126
132
|
|
|
127
133
|
// A session whose most recent assistant turn is a model refusal is
|
|
128
134
|
// excluded from ALL reminder candidates (main-stall and sub-agent
|
|
@@ -212,20 +218,6 @@ export class NotifySilentLiveSessionsUseCase {
|
|
|
212
218
|
);
|
|
213
219
|
continue;
|
|
214
220
|
}
|
|
215
|
-
// Input-state gating: a session whose main REPL is mid-turn — currently
|
|
216
|
-
// running an in-progress tool call, which includes waiting on a
|
|
217
|
-
// long-running sub-agent — cannot accept an injected prompt cleanly, so
|
|
218
|
-
// the reminder is deferred rather than piled into a busy input box. The
|
|
219
|
-
// session stays a candidate, so it is reminded once it becomes
|
|
220
|
-
// input-ready. A tool call pending past
|
|
221
|
-
// IN_PROGRESS_TOOL_CALL_MAX_SUPPRESS_SECONDS is treated as hung and no
|
|
222
|
-
// longer counts as busy (see composeCandidate).
|
|
223
|
-
if (candidate.mainInputBusy) {
|
|
224
|
-
console.log(
|
|
225
|
-
`Skipping ${candidate.sessionName}: main REPL is not in an input-accepting state (in-progress tool call); deferring reminder until it is idle.`,
|
|
226
|
-
);
|
|
227
|
-
continue;
|
|
228
|
-
}
|
|
229
221
|
if (
|
|
230
222
|
!(await this.isHubTaskActive(
|
|
231
223
|
candidate.sessionName,
|
|
@@ -404,16 +396,11 @@ export class NotifySilentLiveSessionsUseCase {
|
|
|
404
396
|
transcriptPathBySessionName,
|
|
405
397
|
);
|
|
406
398
|
const lastOutputBySessionName = new Map<string, number>();
|
|
407
|
-
const inProgressToolCallBySessionName = new Map<string, boolean>();
|
|
408
399
|
for (const activity of activities) {
|
|
409
400
|
lastOutputBySessionName.set(
|
|
410
401
|
activity.sessionName,
|
|
411
402
|
activity.lastOutputEpochSeconds,
|
|
412
403
|
);
|
|
413
|
-
inProgressToolCallBySessionName.set(
|
|
414
|
-
activity.sessionName,
|
|
415
|
-
activity.hasInProgressToolCall,
|
|
416
|
-
);
|
|
417
404
|
}
|
|
418
405
|
|
|
419
406
|
const subAgentsBySessionName =
|
|
@@ -439,8 +426,6 @@ export class NotifySilentLiveSessionsUseCase {
|
|
|
439
426
|
return {
|
|
440
427
|
sessionName,
|
|
441
428
|
mainSilentSeconds,
|
|
442
|
-
mainHasInProgressToolCall:
|
|
443
|
-
inProgressToolCallBySessionName.get(sessionName) ?? false,
|
|
444
429
|
subAgents: subAgentsBySessionName.get(sessionName) ?? [],
|
|
445
430
|
unansweredOwnerCallAgeSeconds:
|
|
446
431
|
unansweredOwnerCallEpochSeconds === undefined
|
|
@@ -476,30 +461,17 @@ export class NotifySilentLiveSessionsUseCase {
|
|
|
476
461
|
// call signature and is intentionally ignored (treated as infinite).
|
|
477
462
|
const suppressedByUnansweredOwnerCall =
|
|
478
463
|
unansweredOwnerCallAgeSeconds !== null;
|
|
479
|
-
//
|
|
480
|
-
//
|
|
481
|
-
//
|
|
482
|
-
//
|
|
483
|
-
//
|
|
484
|
-
// the
|
|
485
|
-
//
|
|
486
|
-
// no pending tool call and is still flagged.
|
|
487
|
-
// The suppression is bounded by the pending tool call's own age
|
|
488
|
-
// (mainSilentSeconds, which for an in-progress tool call equals the age of
|
|
489
|
-
// the pending tool_use line) so it cannot last forever: a session stuck
|
|
490
|
-
// inside a tool call that never returns is reminded once that age exceeds
|
|
491
|
-
// IN_PROGRESS_TOOL_CALL_MAX_SUPPRESS_SECONDS, restoring the ~10-minute
|
|
492
|
-
// stall reminder for a truly hung session instead of suppressing it
|
|
493
|
-
// indefinitely.
|
|
494
|
-
const suppressedByInProgressToolCall =
|
|
495
|
-
snapshot.mainHasInProgressToolCall &&
|
|
496
|
-
mainSilentSeconds !== null &&
|
|
497
|
-
mainSilentSeconds < IN_PROGRESS_TOOL_CALL_MAX_SUPPRESS_SECONDS;
|
|
464
|
+
// The main-stall reminder is driven purely by silence: a session that has
|
|
465
|
+
// produced no assistant output for longer than the threshold is reminded
|
|
466
|
+
// regardless of whether its transcript tail is an in-progress tool_use. A
|
|
467
|
+
// session that merely looks busy (mid-tool-call) can in fact be stuck, so
|
|
468
|
+
// its apparent busyness MUST NOT suppress the reminder; the reminder queues
|
|
469
|
+
// cleanly into the session even when it is mid-turn. The only main-stall
|
|
470
|
+
// suppression is an unanswered owner call, which is a real wait on the owner.
|
|
498
471
|
const mainTriggered =
|
|
499
472
|
mainSilentSeconds !== null &&
|
|
500
473
|
mainSilentSeconds >= thresholds.mainSilentThresholdSeconds &&
|
|
501
|
-
!suppressedByUnansweredOwnerCall
|
|
502
|
-
!suppressedByInProgressToolCall;
|
|
474
|
+
!suppressedByUnansweredOwnerCall;
|
|
503
475
|
if (mainTriggered) {
|
|
504
476
|
sections.push(
|
|
505
477
|
this.messageComposer.composeMainStalledSection(mainSilentSeconds),
|
|
@@ -547,7 +519,6 @@ export class NotifySilentLiveSessionsUseCase {
|
|
|
547
519
|
sessionName: snapshot.sessionName,
|
|
548
520
|
message: sections.join('\n\n'),
|
|
549
521
|
sectionLabels,
|
|
550
|
-
mainInputBusy: suppressedByInProgressToolCall,
|
|
551
522
|
};
|
|
552
523
|
};
|
|
553
524
|
}
|
|
@@ -2,6 +2,6 @@ import { LiveSessionOutputActivity } from '../../domain/entities/LiveSessionOutp
|
|
|
2
2
|
import { SessionOutputActivityRepository } from '../../domain/usecases/adapter-interfaces/SessionOutputActivityRepository';
|
|
3
3
|
export declare class FileSystemSessionOutputActivityRepository implements SessionOutputActivityRepository {
|
|
4
4
|
listSessionOutputActivities: (transcriptPathBySessionName: Map<string, string>) => Promise<LiveSessionOutputActivity[]>;
|
|
5
|
-
private
|
|
5
|
+
private readLastAssistantOutputEpochSeconds;
|
|
6
6
|
}
|
|
7
7
|
//# sourceMappingURL=FileSystemSessionOutputActivityRepository.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileSystemSessionOutputActivityRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/FileSystemSessionOutputActivityRepository.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,iDAAiD,CAAC;AAC5F,OAAO,EAAE,+BAA+B,EAAE,MAAM,0EAA0E,CAAC;
|
|
1
|
+
{"version":3,"file":"FileSystemSessionOutputActivityRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/FileSystemSessionOutputActivityRepository.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,iDAAiD,CAAC;AAC5F,OAAO,EAAE,+BAA+B,EAAE,MAAM,0EAA0E,CAAC;AAqB3H,qBAAa,yCAA0C,YAAW,+BAA+B;IAC/F,2BAA2B,GACzB,6BAA6B,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,KAC/C,OAAO,CAAC,yBAAyB,EAAE,CAAC,CAarC;IAEF,OAAO,CAAC,mCAAmC,CAkCzC;CACH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LiveSessionActivitySnapshot.d.ts","sourceRoot":"","sources":["../../../src/domain/entities/LiveSessionActivitySnapshot.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,wBAAwB,EAAE,OAAO,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,
|
|
1
|
+
{"version":3,"file":"LiveSessionActivitySnapshot.d.ts","sourceRoot":"","sources":["../../../src/domain/entities/LiveSessionActivitySnapshot.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,wBAAwB,EAAE,OAAO,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAC9B,6BAA6B,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9C,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LiveSessionOutputActivity.d.ts","sourceRoot":"","sources":["../../../src/domain/entities/LiveSessionOutputActivity.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,yBAAyB,GAAG;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,sBAAsB,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"LiveSessionOutputActivity.d.ts","sourceRoot":"","sources":["../../../src/domain/entities/LiveSessionOutputActivity.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,yBAAyB,GAAG;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,sBAAsB,EAAE,MAAM,CAAC;CAChC,CAAC"}
|
|
@@ -18,7 +18,6 @@ export declare const DEFAULT_SUBAGENT_RUNNING_THRESHOLD_SECONDS: number;
|
|
|
18
18
|
export declare const DEFAULT_NOTIFICATION_STAGGER_SECONDS = 25;
|
|
19
19
|
export declare const DEFAULT_CANDIDATE_DEBOUNCE_RECENCY_WINDOW_SECONDS: number;
|
|
20
20
|
export declare const DEFAULT_HUB_TASK_STATUS_CACHE_TTL_SECONDS: number;
|
|
21
|
-
export declare const IN_PROGRESS_TOOL_CALL_MAX_SUPPRESS_SECONDS: number;
|
|
22
21
|
export declare const parseHubTaskIssueUrlFromSessionName: (sessionName: string) => string | null;
|
|
23
22
|
export declare const isGitHubIssueOrPullRequestSessionName: (sessionName: string) => boolean;
|
|
24
23
|
export type HubTaskStatusResolver = Pick<IssueRepository, 'getIssueByUrl'>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NotifySilentLiveSessionsUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/NotifySilentLiveSessionsUseCase.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kCAAkC,EAAE,MAAM,yDAAyD,CAAC;AAC7G,OAAO,EAAE,wCAAwC,EAAE,MAAM,+DAA+D,CAAC;AACzH,OAAO,EAAE,uBAAuB,EAAE,MAAM,8CAA8C,CAAC;AACvF,OAAO,EAAE,yBAAyB,EAAE,MAAM,gDAAgD,CAAC;AAC3F,OAAO,EAAE,+BAA+B,EAAE,MAAM,sDAAsD,CAAC;AACvG,OAAO,EAAE,iCAAiC,EAAE,MAAM,wDAAwD,CAAC;AAC3G,OAAO,EAAE,4BAA4B,EAAE,MAAM,mDAAmD,CAAC;AACjG,OAAO,EAAE,mCAAmC,EAAE,MAAM,0DAA0D,CAAC;AAC/G,OAAO,EAAE,qCAAqC,EAAE,MAAM,4DAA4D,CAAC;AACnH,OAAO,EAAE,oCAAoC,EAAE,MAAM,2DAA2D,CAAC;AACjH,OAAO,EAAE,yCAAyC,EAAE,MAAM,gEAAgE,CAAC;AAC3H,OAAO,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAGvE,eAAO,MAAM,qCAAqC,QAAU,CAAC;AAK7D,eAAO,MAAM,2CAA2C,QAAU,CAAC;AACnE,eAAO,MAAM,yCAAyC,QAAS,CAAC;AAChE,eAAO,MAAM,0CAA0C,QAAU,CAAC;AAClE,eAAO,MAAM,oCAAoC,KAAK,CAAC;AACvD,eAAO,MAAM,iDAAiD,QAAU,CAAC;AACzE,eAAO,MAAM,yCAAyC,QAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"NotifySilentLiveSessionsUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/NotifySilentLiveSessionsUseCase.ts"],"names":[],"mappings":"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"}
|