github-issue-tower-defence-management 1.114.0 → 1.114.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/CHANGELOG.md +14 -0
- package/README.md +2 -2
- package/bin/adapter/repositories/FileSystemInteractiveLiveSessionTranscriptResolver.js +36 -27
- package/bin/adapter/repositories/FileSystemInteractiveLiveSessionTranscriptResolver.js.map +1 -1
- package/bin/adapter/repositories/FileSystemSessionOutputActivityRepository.js +14 -14
- package/bin/adapter/repositories/FileSystemSessionOutputActivityRepository.js.map +1 -1
- package/bin/adapter/repositories/FileSystemSessionRecordReader.js +69 -0
- package/bin/adapter/repositories/FileSystemSessionRecordReader.js.map +1 -0
- package/bin/adapter/repositories/LocalProcessLiveSessionProcessSnapshotProvider.js +9 -2
- package/bin/adapter/repositories/LocalProcessLiveSessionProcessSnapshotProvider.js.map +1 -1
- package/bin/domain/usecases/ResolveInteractiveLiveSessionsUseCase.js +43 -0
- package/bin/domain/usecases/ResolveInteractiveLiveSessionsUseCase.js.map +1 -1
- package/bin/domain/usecases/adapter-interfaces/SessionRecordReader.js +3 -0
- package/bin/domain/usecases/adapter-interfaces/SessionRecordReader.js.map +1 -0
- package/package.json +1 -1
- package/src/adapter/repositories/FileSystemInteractiveLiveSessionTranscriptResolver.test.ts +153 -26
- package/src/adapter/repositories/FileSystemInteractiveLiveSessionTranscriptResolver.ts +49 -29
- package/src/adapter/repositories/FileSystemSessionOutputActivityRepository.test.ts +57 -5
- package/src/adapter/repositories/FileSystemSessionOutputActivityRepository.ts +14 -14
- package/src/adapter/repositories/FileSystemSessionRecordReader.test.ts +59 -0
- package/src/adapter/repositories/FileSystemSessionRecordReader.ts +31 -0
- package/src/adapter/repositories/LocalProcessLiveSessionProcessSnapshotProvider.test.ts +51 -0
- package/src/adapter/repositories/LocalProcessLiveSessionProcessSnapshotProvider.ts +10 -1
- package/src/domain/entities/InteractiveLiveSession.ts +1 -0
- package/src/domain/entities/LiveSessionProcessSnapshot.ts +1 -0
- package/src/domain/usecases/NotifySilentLiveSessionsUseCase.test.ts +4 -0
- package/src/domain/usecases/ResolveInteractiveLiveSessionsUseCase.test.ts +142 -59
- package/src/domain/usecases/ResolveInteractiveLiveSessionsUseCase.ts +50 -0
- package/src/domain/usecases/adapter-interfaces/SessionRecordReader.ts +3 -0
- package/types/adapter/repositories/FileSystemInteractiveLiveSessionTranscriptResolver.d.ts +4 -11
- package/types/adapter/repositories/FileSystemInteractiveLiveSessionTranscriptResolver.d.ts.map +1 -1
- package/types/adapter/repositories/FileSystemSessionOutputActivityRepository.d.ts +8 -5
- package/types/adapter/repositories/FileSystemSessionOutputActivityRepository.d.ts.map +1 -1
- package/types/adapter/repositories/FileSystemSessionRecordReader.d.ts +5 -0
- package/types/adapter/repositories/FileSystemSessionRecordReader.d.ts.map +1 -0
- package/types/adapter/repositories/LocalProcessLiveSessionProcessSnapshotProvider.d.ts +3 -1
- package/types/adapter/repositories/LocalProcessLiveSessionProcessSnapshotProvider.d.ts.map +1 -1
- package/types/domain/entities/InteractiveLiveSession.d.ts +1 -0
- package/types/domain/entities/InteractiveLiveSession.d.ts.map +1 -1
- package/types/domain/entities/LiveSessionProcessSnapshot.d.ts +1 -0
- package/types/domain/entities/LiveSessionProcessSnapshot.d.ts.map +1 -1
- package/types/domain/usecases/ResolveInteractiveLiveSessionsUseCase.d.ts +13 -0
- package/types/domain/usecases/ResolveInteractiveLiveSessionsUseCase.d.ts.map +1 -1
- package/types/domain/usecases/adapter-interfaces/SessionRecordReader.d.ts +4 -0
- package/types/domain/usecases/adapter-interfaces/SessionRecordReader.d.ts.map +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [1.114.2](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/compare/v1.114.1...v1.114.2) (2026-06-28)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **silent-notification:** count any transcript entry and resolve non-resume transcripts ([#1061](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/issues/1061)) ([dbb8bb4](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/commit/dbb8bb4171eb4ccd61a9e702a685ce7f9642e43a))
|
|
7
|
+
|
|
8
|
+
## [1.114.1](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/compare/v1.114.0...v1.114.1) (2026-06-28)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **silent-notification:** resolve live transcripts via rotated id and shared projects dir ([#1065](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/issues/1065)) ([95e491a](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/commit/95e491ab813e577c795c5a11d59fb1fab1b035e4)), closes [#1064](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/issues/1064)
|
|
14
|
+
|
|
1
15
|
# [1.114.0](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/compare/v1.113.0...v1.114.0) (2026-06-28)
|
|
2
16
|
|
|
3
17
|
|
package/README.md
CHANGED
|
@@ -556,9 +556,9 @@ For each `In Tmux by human` issue with no live session, the reconciler launches
|
|
|
556
556
|
|
|
557
557
|
Each schedule cycle, when `silentNotificationEnabled` is true, also inspects every live interactive Claude Code session and sends a short self-check reminder into a session via `tmux send-keys` when either of two independent conditions holds. The reminder is composed of only the sections whose condition is met, so a session receives one combined message containing one or both sections. When `silentNotificationEnabled` is not set, the entire step is a no-op even if the daemon picks up its configuration automatically.
|
|
558
558
|
|
|
559
|
-
Sessions are selected purely from the live process tree, independently of session naming or any GitHub issue linkage: every live tmux session is taken, the descendants of each session's pane processes are walked, and the first descendant that is an interactive Claude Code process (its command line contains `claude` and does not contain the owner-handover marker `Take ownership of`, and its environment exposes both `CLAUDE_CODE_SESSION_ID` and `CLAUDE_CONFIG_DIR`) is taken as that session's process. Both issue-url-named sessions and plain-named sessions (for example `workbench`) are selected equally. Because the walk is anchored on tmux panes, background owner-handover spawns, the preparation daemon, and monitor processes — none of which run inside an interactive tmux pane — are excluded; the owner-handover marker check is an additional guard. Each selected session's transcript is then resolved from
|
|
559
|
+
Sessions are selected purely from the live process tree, independently of session naming or any GitHub issue linkage: every live tmux session is taken, the descendants of each session's pane processes are walked, and the first descendant that is an interactive Claude Code process (its command line contains `claude` and does not contain the owner-handover marker `Take ownership of`, and its environment exposes both `CLAUDE_CODE_SESSION_ID` and `CLAUDE_CONFIG_DIR`) is taken as that session's process. Both issue-url-named sessions and plain-named sessions (for example `workbench`) are selected equally. Because the walk is anchored on tmux panes, background owner-handover spawns, the preparation daemon, and monitor processes — none of which run inside an interactive tmux pane — are excluded; the owner-handover marker check is an additional guard. Each selected session's transcript is then resolved by scanning the `projects/<cwd-slug>/` subdirectories of two roots — the per-session `<CLAUDE_CONFIG_DIR>/projects/` and the shared `~/.claude/projects/` — for a `<sessionId>.jsonl` file named by any of the session's candidate session ids. The candidate ids are derived from the process tree, in priority order: the current session id recorded in `<CLAUDE_CONFIG_DIR>/sessions/<pid>.json` (the session id rotates on resume or compaction, and this record holds the current value), then the interactive process's own launch id from the `CLAUDE_CODE_SESSION_ID` environment variable, then the distinct ids propagated to its descendant processes, all deduped. Searching the shared root and the rotated current id is required because, for a resumed or compacted session, the actively-written transcript is named by the current id and lives under the shared root rather than under the per-session config directory; the descendant-propagated ids are required because, for a session started without `--resume`, the own launch id names no transcript on disk and the live transcript is named by the descendant id. The candidate files are matched across both roots by existence; the most recently modified match is used only as a tiebreak when several candidate files exist. This way a non-resume session and a session that has no issue URL both resolve just as reliably as a resume, issue-url-named one.
|
|
560
560
|
|
|
561
|
-
The main-session stalled section is sent when the session's main output has been idle for at least `mainSilentThresholdSeconds`, unless the session is currently waiting on the owner (in that case the silence is expected and the section is suppressed). Idle time is computed from the timestamp of the latest
|
|
561
|
+
The main-session stalled section is sent when the session's main output has been idle for at least `mainSilentThresholdSeconds`, unless the session is currently waiting on the owner (in that case the silence is expected and the section is suppressed). Idle time is computed from the timestamp of the latest entry of any kind in the session's resolved transcript rather than from the transcript file modification time, so a session that keeps appending tool results, owner replies, or any other entry type while emitting no assistant text still counts as active and is not mistaken for a silent one. Whether a session is waiting on the owner is determined through an injectable port; the built-in default reports no session as waiting, so the suppression is only applied when a host provides an implementation. When `ownerCallMarker` is configured, a transcript-based implementation is used: it reads each session's resolved transcript and treats the session as waiting on the owner when the latest entry containing `ownerCallMarker` is newer (by full timestamp) than the latest genuine owner reply. A self-check reminder that the monitor injects into a session via `tmux send-keys` itself lands in that session's transcript as a `user` text entry; every injected reminder carries a fixed sentinel tag (`[TDPM_SILENT_SESSION_SELF_CHECK_REMINDER]`), and a `user` entry whose text contains that sentinel is not counted as a genuine owner reply. This prevents the monitor's own reminder from being mistaken for the owner answering, which would otherwise make a genuinely waiting session stop being suppressed.
|
|
562
562
|
|
|
563
563
|
The sub-process section is sent, regardless of main output, when at least one sub-process of the session has been output-idle for `subAgentSilentThresholdSeconds` or has been running for `subAgentRunningThresholdSeconds`; the message lists each matched sub-process with its idle and running minutes. Sub-processes are discovered in one of two ways: when `subAgentTranscriptRootDirectory` is configured, each session's `subagents/agent-<id>.jsonl` transcripts are scanned, finished sub-agents (latest transcript entry `stop_reason` equal to `end_turn` or `stop_sequence`) are skipped, and idle time is taken from the transcript file modification time (following symlinks) while running time is taken from its first entry timestamp; otherwise sub-processes are discovered by matching `subAgentProcessMatchPattern` against process command lines.
|
|
564
564
|
|
|
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.FileSystemInteractiveLiveSessionTranscriptResolver = void 0;
|
|
37
37
|
const fs = __importStar(require("fs"));
|
|
38
|
+
const os = __importStar(require("os"));
|
|
38
39
|
const path = __importStar(require("path"));
|
|
39
40
|
const modifiedEpochMs = (filePath) => {
|
|
40
41
|
try {
|
|
@@ -45,19 +46,10 @@ const modifiedEpochMs = (filePath) => {
|
|
|
45
46
|
return null;
|
|
46
47
|
}
|
|
47
48
|
};
|
|
48
|
-
|
|
49
|
-
* Resolves the real transcript path of an interactive Claude Code session from
|
|
50
|
-
* the session id and config directory taken from the session's process
|
|
51
|
-
* environment. The transcript lives at
|
|
52
|
-
* `<configDir>/projects/<cwd-slug>/<sessionId>.jsonl`; this resolver scans the
|
|
53
|
-
* `projects` subdirectories for a file named `<sessionId>.jsonl` and returns the
|
|
54
|
-
* most recently modified match. Because resolution is keyed on the process
|
|
55
|
-
* session id rather than on a session name or issue URL, a plain-named session
|
|
56
|
-
* (for example one named `workbench`) resolves just as well as an issue-url
|
|
57
|
-
* named one.
|
|
58
|
-
*/
|
|
49
|
+
const defaultSharedProjectsDirectory = () => path.join(os.homedir(), '.claude', 'projects');
|
|
59
50
|
class FileSystemInteractiveLiveSessionTranscriptResolver {
|
|
60
|
-
constructor() {
|
|
51
|
+
constructor(sharedProjectsDirectory = defaultSharedProjectsDirectory()) {
|
|
52
|
+
this.sharedProjectsDirectory = sharedProjectsDirectory;
|
|
61
53
|
this.resolveTranscriptPaths = (sessions) => {
|
|
62
54
|
const resolved = new Map();
|
|
63
55
|
for (const session of sessions) {
|
|
@@ -69,7 +61,34 @@ class FileSystemInteractiveLiveSessionTranscriptResolver {
|
|
|
69
61
|
return resolved;
|
|
70
62
|
};
|
|
71
63
|
this.resolveTranscriptPath = (session) => {
|
|
72
|
-
const
|
|
64
|
+
const projectsDirectories = this.listProjectsDirectories(session.configDir);
|
|
65
|
+
let latestPath = null;
|
|
66
|
+
let latestEpochMs = -Infinity;
|
|
67
|
+
for (const candidateSessionId of session.candidateSessionIds) {
|
|
68
|
+
const fileName = `${candidateSessionId}.jsonl`;
|
|
69
|
+
for (const projectsDirectory of projectsDirectories) {
|
|
70
|
+
for (const candidate of this.listCandidatePaths(projectsDirectory, fileName)) {
|
|
71
|
+
const epochMs = modifiedEpochMs(candidate);
|
|
72
|
+
if (epochMs === null) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (epochMs > latestEpochMs) {
|
|
76
|
+
latestEpochMs = epochMs;
|
|
77
|
+
latestPath = candidate;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return latestPath;
|
|
83
|
+
};
|
|
84
|
+
this.listProjectsDirectories = (configDir) => {
|
|
85
|
+
const perSessionProjectsDirectory = path.join(configDir, 'projects');
|
|
86
|
+
if (perSessionProjectsDirectory === this.sharedProjectsDirectory) {
|
|
87
|
+
return [perSessionProjectsDirectory];
|
|
88
|
+
}
|
|
89
|
+
return [perSessionProjectsDirectory, this.sharedProjectsDirectory];
|
|
90
|
+
};
|
|
91
|
+
this.listCandidatePaths = (projectsDirectory, fileName) => {
|
|
73
92
|
let projectEntries;
|
|
74
93
|
try {
|
|
75
94
|
projectEntries = fs.readdirSync(projectsDirectory, {
|
|
@@ -77,26 +96,16 @@ class FileSystemInteractiveLiveSessionTranscriptResolver {
|
|
|
77
96
|
});
|
|
78
97
|
}
|
|
79
98
|
catch {
|
|
80
|
-
return
|
|
99
|
+
return [];
|
|
81
100
|
}
|
|
82
|
-
const
|
|
83
|
-
let latestPath = null;
|
|
84
|
-
let latestEpochMs = -Infinity;
|
|
101
|
+
const candidatePaths = [];
|
|
85
102
|
for (const projectEntry of projectEntries) {
|
|
86
103
|
if (!projectEntry.isDirectory()) {
|
|
87
104
|
continue;
|
|
88
105
|
}
|
|
89
|
-
|
|
90
|
-
const epochMs = modifiedEpochMs(candidate);
|
|
91
|
-
if (epochMs === null) {
|
|
92
|
-
continue;
|
|
93
|
-
}
|
|
94
|
-
if (epochMs > latestEpochMs) {
|
|
95
|
-
latestEpochMs = epochMs;
|
|
96
|
-
latestPath = candidate;
|
|
97
|
-
}
|
|
106
|
+
candidatePaths.push(path.join(projectsDirectory, projectEntry.name, fileName));
|
|
98
107
|
}
|
|
99
|
-
return
|
|
108
|
+
return candidatePaths;
|
|
100
109
|
};
|
|
101
110
|
}
|
|
102
111
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileSystemInteractiveLiveSessionTranscriptResolver.js","sourceRoot":"","sources":["../../../src/adapter/repositories/FileSystemInteractiveLiveSessionTranscriptResolver.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAyB;AACzB,2CAA6B;AAI7B,MAAM,eAAe,GAAG,CAAC,QAAgB,EAAiB,EAAE;IAC1D,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACpC,OAAO,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AAEF
|
|
1
|
+
{"version":3,"file":"FileSystemInteractiveLiveSessionTranscriptResolver.js","sourceRoot":"","sources":["../../../src/adapter/repositories/FileSystemInteractiveLiveSessionTranscriptResolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -48,25 +48,28 @@ const parseEpochMilliseconds = (timestamp) => {
|
|
|
48
48
|
return Number.isNaN(parsed) ? null : parsed;
|
|
49
49
|
};
|
|
50
50
|
/**
|
|
51
|
-
* Reads the last main-session
|
|
51
|
+
* Reads the last main-session activity time for each live session from its
|
|
52
52
|
* already-resolved transcript path. Idle time is computed from the timestamp of
|
|
53
|
-
* the latest
|
|
54
|
-
*
|
|
55
|
-
*
|
|
53
|
+
* the latest entry of any kind (assistant text, owner replies, tool results, or
|
|
54
|
+
* any other entry type) rather than from the transcript file modification time.
|
|
55
|
+
* Because a session that is actively running tool calls keeps appending entries
|
|
56
|
+
* such as `user` and `tool_result` even while it emits no assistant text, every
|
|
57
|
+
* entry with a parseable timestamp counts as activity, so a working session is
|
|
58
|
+
* not mistaken for a silent one.
|
|
56
59
|
*/
|
|
57
60
|
class FileSystemSessionOutputActivityRepository {
|
|
58
61
|
constructor() {
|
|
59
62
|
this.listSessionOutputActivities = async (transcriptPathBySessionName) => {
|
|
60
63
|
const activities = [];
|
|
61
64
|
for (const [sessionName, transcriptPath] of transcriptPathBySessionName) {
|
|
62
|
-
const lastOutputEpochSeconds = this.
|
|
65
|
+
const lastOutputEpochSeconds = this.readLastActivityEpochSeconds(transcriptPath);
|
|
63
66
|
if (lastOutputEpochSeconds !== null) {
|
|
64
67
|
activities.push({ sessionName, lastOutputEpochSeconds });
|
|
65
68
|
}
|
|
66
69
|
}
|
|
67
70
|
return activities;
|
|
68
71
|
};
|
|
69
|
-
this.
|
|
72
|
+
this.readLastActivityEpochSeconds = (transcriptPath) => {
|
|
70
73
|
let content;
|
|
71
74
|
try {
|
|
72
75
|
content = fs.readFileSync(transcriptPath, 'utf8');
|
|
@@ -74,7 +77,7 @@ class FileSystemSessionOutputActivityRepository {
|
|
|
74
77
|
catch {
|
|
75
78
|
return null;
|
|
76
79
|
}
|
|
77
|
-
let
|
|
80
|
+
let lastActivityEpochMs = null;
|
|
78
81
|
for (const line of content.split('\n')) {
|
|
79
82
|
const trimmed = line.trim();
|
|
80
83
|
if (trimmed.length === 0) {
|
|
@@ -90,21 +93,18 @@ class FileSystemSessionOutputActivityRepository {
|
|
|
90
93
|
if (!isRecord(parsed)) {
|
|
91
94
|
continue;
|
|
92
95
|
}
|
|
93
|
-
if (readString(parsed, 'type') !== 'assistant') {
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
96
|
const epochMs = parseEpochMilliseconds(readString(parsed, 'timestamp'));
|
|
97
97
|
if (epochMs === null) {
|
|
98
98
|
continue;
|
|
99
99
|
}
|
|
100
|
-
if (
|
|
101
|
-
|
|
100
|
+
if (lastActivityEpochMs === null || epochMs > lastActivityEpochMs) {
|
|
101
|
+
lastActivityEpochMs = epochMs;
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
|
-
if (
|
|
104
|
+
if (lastActivityEpochMs === null) {
|
|
105
105
|
return null;
|
|
106
106
|
}
|
|
107
|
-
return Math.floor(
|
|
107
|
+
return Math.floor(lastActivityEpochMs / 1000);
|
|
108
108
|
};
|
|
109
109
|
}
|
|
110
110
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileSystemSessionOutputActivityRepository.js","sourceRoot":"","sources":["../../../src/adapter/repositories/FileSystemSessionOutputActivityRepository.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAyB;AAIzB,MAAM,QAAQ,GAAG,CAAC,KAAc,EAAoC,EAAE,CACpE,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC;AAE9C,MAAM,UAAU,GAAG,CACjB,KAA8B,EAC9B,GAAW,EACI,EAAE;IACjB,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7B,OAAO,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1D,CAAC,CAAC;AAEF,MAAM,sBAAsB,GAAG,CAAC,SAAwB,EAAiB,EAAE;IACzE,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACrC,OAAO,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;AAC9C,CAAC,CAAC;AAEF
|
|
1
|
+
{"version":3,"file":"FileSystemSessionOutputActivityRepository.js","sourceRoot":"","sources":["../../../src/adapter/repositories/FileSystemSessionOutputActivityRepository.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.FileSystemSessionRecordReader = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const isRecord = (value) => typeof value === 'object' && value !== null;
|
|
40
|
+
class FileSystemSessionRecordReader {
|
|
41
|
+
constructor() {
|
|
42
|
+
this.readCurrentSessionId = (configDir, pid) => {
|
|
43
|
+
const recordPath = path.join(configDir, 'sessions', `${pid}.json`);
|
|
44
|
+
let content;
|
|
45
|
+
try {
|
|
46
|
+
content = fs.readFileSync(recordPath, 'utf8');
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
let parsed;
|
|
52
|
+
try {
|
|
53
|
+
parsed = JSON.parse(content);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
if (!isRecord(parsed)) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
const sessionId = parsed.sessionId;
|
|
62
|
+
return typeof sessionId === 'string' && sessionId.length > 0
|
|
63
|
+
? sessionId
|
|
64
|
+
: null;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
exports.FileSystemSessionRecordReader = FileSystemSessionRecordReader;
|
|
69
|
+
//# sourceMappingURL=FileSystemSessionRecordReader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileSystemSessionRecordReader.js","sourceRoot":"","sources":["../../../src/adapter/repositories/FileSystemSessionRecordReader.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAyB;AACzB,2CAA6B;AAG7B,MAAM,QAAQ,GAAG,CAAC,KAAc,EAAoC,EAAE,CACpE,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC;AAE9C,MAAa,6BAA6B;IAA1C;QACE,yBAAoB,GAAG,CAAC,SAAiB,EAAE,GAAW,EAAiB,EAAE;YACvE,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC;YACnE,IAAI,OAAe,CAAC;YACpB,IAAI,CAAC;gBACH,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;YAChD,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,IAAI,CAAC;YACd,CAAC;YACD,IAAI,MAAe,CAAC;YACpB,IAAI,CAAC;gBACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC/B,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,IAAI,CAAC;YACd,CAAC;YACD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBACtB,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;YACnC,OAAO,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC;gBAC1D,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,IAAI,CAAC;QACX,CAAC,CAAC;IACJ,CAAC;CAAA;AAvBD,sEAuBC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.LocalProcessLiveSessionProcessSnapshotProvider = void 0;
|
|
4
|
+
const FileSystemSessionRecordReader_1 = require("./FileSystemSessionRecordReader");
|
|
4
5
|
const SESSION_ID_ENV_KEY = 'CLAUDE_CODE_SESSION_ID';
|
|
5
6
|
const CONFIG_DIR_ENV_KEY = 'CLAUDE_CONFIG_DIR';
|
|
6
7
|
/**
|
|
@@ -11,9 +12,10 @@ const CONFIG_DIR_ENV_KEY = 'CLAUDE_CONFIG_DIR';
|
|
|
11
12
|
* pure resolver, so all host access is contained in this adapter.
|
|
12
13
|
*/
|
|
13
14
|
class LocalProcessLiveSessionProcessSnapshotProvider {
|
|
14
|
-
constructor(localCommandRunner, environReader) {
|
|
15
|
+
constructor(localCommandRunner, environReader, sessionRecordReader = new FileSystemSessionRecordReader_1.FileSystemSessionRecordReader()) {
|
|
15
16
|
this.localCommandRunner = localCommandRunner;
|
|
16
17
|
this.environReader = environReader;
|
|
18
|
+
this.sessionRecordReader = sessionRecordReader;
|
|
17
19
|
this.getSnapshot = async () => {
|
|
18
20
|
const sessionNames = await this.listSessionNames();
|
|
19
21
|
const sessions = [];
|
|
@@ -59,12 +61,17 @@ class LocalProcessLiveSessionProcessSnapshotProvider {
|
|
|
59
61
|
const ppid = Number(match[2]);
|
|
60
62
|
const commandLine = match[3].trim();
|
|
61
63
|
const environ = this.environReader.readEnviron(pid);
|
|
64
|
+
const configDir = environ?.[CONFIG_DIR_ENV_KEY] ?? null;
|
|
65
|
+
const currentSessionId = configDir === null
|
|
66
|
+
? null
|
|
67
|
+
: this.sessionRecordReader.readCurrentSessionId(configDir, pid);
|
|
62
68
|
processes.push({
|
|
63
69
|
pid,
|
|
64
70
|
ppid,
|
|
65
71
|
commandLine,
|
|
66
72
|
sessionId: environ?.[SESSION_ID_ENV_KEY] ?? null,
|
|
67
|
-
|
|
73
|
+
currentSessionId,
|
|
74
|
+
configDir,
|
|
68
75
|
});
|
|
69
76
|
}
|
|
70
77
|
return processes;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LocalProcessLiveSessionProcessSnapshotProvider.js","sourceRoot":"","sources":["../../../src/adapter/repositories/LocalProcessLiveSessionProcessSnapshotProvider.ts"],"names":[],"mappings":";;;AASA,MAAM,kBAAkB,GAAG,wBAAwB,CAAC;AACpD,MAAM,kBAAkB,GAAG,mBAAmB,CAAC;AAE/C;;;;;;GAMG;AACH,MAAa,8CAA8C;IACzD,YACmB,kBAAsC,EACtC,aAAmC;
|
|
1
|
+
{"version":3,"file":"LocalProcessLiveSessionProcessSnapshotProvider.js","sourceRoot":"","sources":["../../../src/adapter/repositories/LocalProcessLiveSessionProcessSnapshotProvider.ts"],"names":[],"mappings":"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"}
|
|
@@ -52,14 +52,57 @@ class ResolveInteractiveLiveSessionsUseCase {
|
|
|
52
52
|
interactiveProcess.configDir === null) {
|
|
53
53
|
continue;
|
|
54
54
|
}
|
|
55
|
+
const candidateSessionIds = this.collectCandidateSessionIds(interactiveProcess, childrenByPpid);
|
|
55
56
|
sessions.push({
|
|
56
57
|
sessionName: session.sessionName,
|
|
57
58
|
sessionId: interactiveProcess.sessionId,
|
|
59
|
+
candidateSessionIds,
|
|
58
60
|
configDir: interactiveProcess.configDir,
|
|
59
61
|
});
|
|
60
62
|
}
|
|
61
63
|
return sessions;
|
|
62
64
|
};
|
|
65
|
+
/**
|
|
66
|
+
* Collects the distinct session ids that may name the actively-written
|
|
67
|
+
* transcript on disk, in priority order. The rotated current session id
|
|
68
|
+
* recorded for the interactive process is first, because for a resumed or
|
|
69
|
+
* compacted session the id rotates and the live transcript is named by the
|
|
70
|
+
* current id. The interactive process's own launch id follows, then the
|
|
71
|
+
* distinct ids propagated to its descendant processes. For a `--resume`
|
|
72
|
+
* session these ids coincide, yielding a single id; for a non-resume session
|
|
73
|
+
* the own (launch) id names no transcript and the live transcript is named by
|
|
74
|
+
* the descendant-propagated id, which is included here so the resolver can
|
|
75
|
+
* find the actively-written file.
|
|
76
|
+
*/
|
|
77
|
+
this.collectCandidateSessionIds = (interactiveProcess, childrenByPpid) => {
|
|
78
|
+
const candidateSessionIds = [];
|
|
79
|
+
const seenSessionIds = new Set();
|
|
80
|
+
const pushSessionId = (sessionId) => {
|
|
81
|
+
if (sessionId !== null && !seenSessionIds.has(sessionId)) {
|
|
82
|
+
seenSessionIds.add(sessionId);
|
|
83
|
+
candidateSessionIds.push(sessionId);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
pushSessionId(interactiveProcess.currentSessionId);
|
|
87
|
+
const visitedPids = new Set();
|
|
88
|
+
const queue = [interactiveProcess];
|
|
89
|
+
let head = 0;
|
|
90
|
+
while (head < queue.length) {
|
|
91
|
+
const process = queue[head];
|
|
92
|
+
head += 1;
|
|
93
|
+
if (visitedPids.has(process.pid)) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
visitedPids.add(process.pid);
|
|
97
|
+
pushSessionId(process.sessionId);
|
|
98
|
+
for (const child of childrenByPpid.get(process.pid) ?? []) {
|
|
99
|
+
if (!visitedPids.has(child.pid)) {
|
|
100
|
+
queue.push(child);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return candidateSessionIds;
|
|
105
|
+
};
|
|
63
106
|
this.findInteractiveProcess = (panePids, processByPid, childrenByPpid) => {
|
|
64
107
|
const visited = new Set();
|
|
65
108
|
const queue = [...panePids];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ResolveInteractiveLiveSessionsUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/ResolveInteractiveLiveSessionsUseCase.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"ResolveInteractiveLiveSessionsUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/ResolveInteractiveLiveSessionsUseCase.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionRecordReader.js","sourceRoot":"","sources":["../../../../src/domain/usecases/adapter-interfaces/SessionRecordReader.ts"],"names":[],"mappings":""}
|