github-issue-tower-defence-management 1.97.4 → 1.98.1
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/close-manual-prs.yml +48 -0
- package/.github/workflows/codeql.yml +1 -1
- package/.github/workflows/console-ui.yml +1 -1
- package/.github/workflows/empty-format-test-job.yml +1 -1
- package/.github/workflows/format.yml +1 -1
- package/.github/workflows/publish.yml +1 -1
- package/.github/workflows/test.yml +1 -1
- package/CHANGELOG.md +14 -0
- package/README.md +12 -0
- package/bin/adapter/entry-points/cli/index.js +62 -0
- package/bin/adapter/entry-points/cli/index.js.map +1 -1
- package/bin/adapter/entry-points/console/ui-dist/assets/index-DR2UiWOI.js +101 -0
- package/bin/adapter/entry-points/console/ui-dist/index.html +1 -1
- package/bin/adapter/entry-points/handlers/InTmuxByHumanSessionTokenCountHandler.js +48 -0
- package/bin/adapter/entry-points/handlers/InTmuxByHumanSessionTokenCountHandler.js.map +1 -0
- package/bin/adapter/repositories/ProcClaudeInteractiveSessionRepository.js +145 -0
- package/bin/adapter/repositories/ProcClaudeInteractiveSessionRepository.js.map +1 -0
- package/bin/domain/usecases/InTmuxByHumanSessionTokenCountUseCase.js +41 -0
- package/bin/domain/usecases/InTmuxByHumanSessionTokenCountUseCase.js.map +1 -0
- package/bin/domain/usecases/adapter-interfaces/ClaudeInteractiveSessionRepository.js +3 -0
- package/bin/domain/usecases/adapter-interfaces/ClaudeInteractiveSessionRepository.js.map +1 -0
- package/package.json +2 -2
- package/src/adapter/entry-points/cli/index.ts +120 -0
- package/src/adapter/entry-points/console/ui-dist/assets/index-DR2UiWOI.js +101 -0
- package/src/adapter/entry-points/console/ui-dist/index.html +1 -1
- package/src/adapter/entry-points/handlers/InTmuxByHumanSessionTokenCountHandler.test.ts +123 -0
- package/src/adapter/entry-points/handlers/InTmuxByHumanSessionTokenCountHandler.ts +77 -0
- package/src/adapter/repositories/ProcClaudeInteractiveSessionRepository.test.ts +184 -0
- package/src/adapter/repositories/ProcClaudeInteractiveSessionRepository.ts +138 -0
- package/src/domain/usecases/InTmuxByHumanSessionTokenCountUseCase.test.ts +169 -0
- package/src/domain/usecases/InTmuxByHumanSessionTokenCountUseCase.ts +63 -0
- package/src/domain/usecases/adapter-interfaces/ClaudeInteractiveSessionRepository.ts +9 -0
- package/types/adapter/entry-points/cli/index.d.ts.map +1 -1
- package/types/adapter/entry-points/handlers/InTmuxByHumanSessionTokenCountHandler.d.ts +18 -0
- package/types/adapter/entry-points/handlers/InTmuxByHumanSessionTokenCountHandler.d.ts.map +1 -0
- package/types/adapter/repositories/ProcClaudeInteractiveSessionRepository.d.ts +11 -0
- package/types/adapter/repositories/ProcClaudeInteractiveSessionRepository.d.ts.map +1 -0
- package/types/domain/usecases/InTmuxByHumanSessionTokenCountUseCase.d.ts +17 -0
- package/types/domain/usecases/InTmuxByHumanSessionTokenCountUseCase.d.ts.map +1 -0
- package/types/domain/usecases/adapter-interfaces/ClaudeInteractiveSessionRepository.d.ts +9 -0
- package/types/domain/usecases/adapter-interfaces/ClaudeInteractiveSessionRepository.d.ts.map +1 -0
- package/bin/adapter/entry-points/console/ui-dist/assets/index-BFKRWKvS.js +0 -101
- package/src/adapter/entry-points/console/ui-dist/assets/index-BFKRWKvS.js +0 -101
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>TDPM Console</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-DR2UiWOI.js"></script>
|
|
8
8
|
<link rel="stylesheet" crossorigin href="/assets/index-CzVHU81K.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InTmuxByHumanSessionTokenCountHandler = void 0;
|
|
4
|
+
const InTmuxByHumanSessionTokenCountUseCase_1 = require("../../../domain/usecases/InTmuxByHumanSessionTokenCountUseCase");
|
|
5
|
+
const ProcClaudeInteractiveSessionRepository_1 = require("../../repositories/ProcClaudeInteractiveSessionRepository");
|
|
6
|
+
const TokenListLoader_1 = require("../../proxy/TokenListLoader");
|
|
7
|
+
const OauthTokenSelectHandler_1 = require("./OauthTokenSelectHandler");
|
|
8
|
+
class InTmuxByHumanSessionTokenCountHandler {
|
|
9
|
+
constructor(useCase = new InTmuxByHumanSessionTokenCountUseCase_1.InTmuxByHumanSessionTokenCountUseCase(), interactiveSessionRepository = new ProcClaudeInteractiveSessionRepository_1.ProcClaudeInteractiveSessionRepository()) {
|
|
10
|
+
this.useCase = useCase;
|
|
11
|
+
this.interactiveSessionRepository = interactiveSessionRepository;
|
|
12
|
+
this.handle = (input) => {
|
|
13
|
+
const tokenListJsonPath = (0, OauthTokenSelectHandler_1.resolveTokenListJsonPath)(input.tokenListJsonPath);
|
|
14
|
+
if (tokenListJsonPath === null) {
|
|
15
|
+
return {
|
|
16
|
+
lines: [],
|
|
17
|
+
diagnostics: [
|
|
18
|
+
'No token list path provided. Pass --tokenListJsonPath or set CLAUDE_CODE_OAUTH_TOKEN_LIST_JSON_PATH.',
|
|
19
|
+
],
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
const entries = (0, TokenListLoader_1.loadTokenEntries)(tokenListJsonPath);
|
|
23
|
+
if (entries === null) {
|
|
24
|
+
return {
|
|
25
|
+
lines: [],
|
|
26
|
+
diagnostics: [
|
|
27
|
+
`No usable token entries loaded from ${tokenListJsonPath}.`,
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
const candidates = entries.map(({ name, token }) => ({
|
|
32
|
+
name,
|
|
33
|
+
token,
|
|
34
|
+
snapshot: null,
|
|
35
|
+
}));
|
|
36
|
+
const interactiveSessions = this.interactiveSessionRepository.listInteractiveSessions();
|
|
37
|
+
const result = this.useCase.run(candidates, interactiveSessions, input.issues);
|
|
38
|
+
const lines = result.counts.map((count) => `${count.name}\t${count.count}`);
|
|
39
|
+
const totalSessions = result.counts.reduce((sum, count) => sum + count.count, 0);
|
|
40
|
+
const diagnostics = [
|
|
41
|
+
`Counted ${totalSessions} live In-Tmux-by-human session(s) across ${result.counts.length} token(s).`,
|
|
42
|
+
];
|
|
43
|
+
return { lines, diagnostics };
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
exports.InTmuxByHumanSessionTokenCountHandler = InTmuxByHumanSessionTokenCountHandler;
|
|
48
|
+
//# sourceMappingURL=InTmuxByHumanSessionTokenCountHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InTmuxByHumanSessionTokenCountHandler.js","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/InTmuxByHumanSessionTokenCountHandler.ts"],"names":[],"mappings":";;;AAEA,0HAAuH;AAEvH,sHAAmH;AACnH,iEAA+D;AAC/D,uEAAqE;AAYrE,MAAa,qCAAqC;IAChD,YACmB,UAAiD,IAAI,6EAAqC,EAAE,EAC5F,+BAAmE,IAAI,+EAAsC,EAAE;QAD/G,YAAO,GAAP,OAAO,CAAqF;QAC5F,iCAA4B,GAA5B,4BAA4B,CAAmF;QAGlI,WAAM,GAAG,CACP,KAAiD,EACJ,EAAE;YAC/C,MAAM,iBAAiB,GAAG,IAAA,kDAAwB,EAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;YAC5E,IAAI,iBAAiB,KAAK,IAAI,EAAE,CAAC;gBAC/B,OAAO;oBACL,KAAK,EAAE,EAAE;oBACT,WAAW,EAAE;wBACX,sGAAsG;qBACvG;iBACF,CAAC;YACJ,CAAC;YAED,MAAM,OAAO,GAAG,IAAA,kCAAgB,EAAC,iBAAiB,CAAC,CAAC;YACpD,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;gBACrB,OAAO;oBACL,KAAK,EAAE,EAAE;oBACT,WAAW,EAAE;wBACX,uCAAuC,iBAAiB,GAAG;qBAC5D;iBACF,CAAC;YACJ,CAAC;YAED,MAAM,UAAU,GAA0B,OAAO,CAAC,GAAG,CACnD,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;gBACpB,IAAI;gBACJ,KAAK;gBACL,QAAQ,EAAE,IAAI;aACf,CAAC,CACH,CAAC;YAEF,MAAM,mBAAmB,GACvB,IAAI,CAAC,4BAA4B,CAAC,uBAAuB,EAAE,CAAC;YAE9D,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAC7B,UAAU,EACV,mBAAmB,EACnB,KAAK,CAAC,MAAM,CACb,CAAC;YAEF,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;YAE5E,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CACxC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,GAAG,KAAK,CAAC,KAAK,EACjC,CAAC,CACF,CAAC;YACF,MAAM,WAAW,GAAG;gBAClB,WAAW,aAAa,4CAA4C,MAAM,CAAC,MAAM,CAAC,MAAM,YAAY;aACrG,CAAC;YAEF,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;QAChC,CAAC,CAAC;IArDC,CAAC;CAsDL;AA1DD,sFA0DC"}
|
|
@@ -0,0 +1,145 @@
|
|
|
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.ProcClaudeInteractiveSessionRepository = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const DEFAULT_PROC_DIRECTORY = '/proc';
|
|
40
|
+
const OAUTH_TOKEN_ENVIRON_KEY = 'CLAUDE_CODE_OAUTH_TOKEN';
|
|
41
|
+
const SESSION_ID_ENVIRON_KEY = 'CLAUDE_CODE_SESSION_ID';
|
|
42
|
+
const NAME_ARGUMENT = '--name';
|
|
43
|
+
const TAKE_OWNERSHIP_MARKER = 'Take ownership';
|
|
44
|
+
const isIssueUrl = (value) => value.startsWith('http://') || value.startsWith('https://');
|
|
45
|
+
const parseCommandLineArguments = (cmdline) => cmdline.split('\0').filter((argument) => argument.length > 0);
|
|
46
|
+
const extractIssueUrl = (commandArguments) => {
|
|
47
|
+
for (let index = 0; index < commandArguments.length - 1; index += 1) {
|
|
48
|
+
if (commandArguments[index] === NAME_ARGUMENT) {
|
|
49
|
+
const value = commandArguments[index + 1] ?? '';
|
|
50
|
+
if (isIssueUrl(value)) {
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
};
|
|
57
|
+
const isTakeOwnershipSpawn = (commandArguments) => commandArguments.some((argument) => argument.includes(TAKE_OWNERSHIP_MARKER));
|
|
58
|
+
class ProcClaudeInteractiveSessionRepository {
|
|
59
|
+
constructor(procDirectory = DEFAULT_PROC_DIRECTORY) {
|
|
60
|
+
this.procDirectory = procDirectory;
|
|
61
|
+
this.listInteractiveSessions = () => {
|
|
62
|
+
const interactiveSessions = [];
|
|
63
|
+
for (const pidDirectory of this.listProcessIdDirectories()) {
|
|
64
|
+
const interactiveSession = this.readInteractiveSession(pidDirectory);
|
|
65
|
+
if (interactiveSession !== null) {
|
|
66
|
+
interactiveSessions.push(interactiveSession);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return interactiveSessions;
|
|
70
|
+
};
|
|
71
|
+
this.listProcessIdDirectories = () => {
|
|
72
|
+
let entries;
|
|
73
|
+
try {
|
|
74
|
+
entries = fs.readdirSync(this.procDirectory);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
return entries.filter((entry) => /^\d+$/.test(entry));
|
|
80
|
+
};
|
|
81
|
+
this.readInteractiveSession = (processIdDirectory) => {
|
|
82
|
+
const commandArguments = this.readCommandArguments(processIdDirectory);
|
|
83
|
+
if (commandArguments === null) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
if (isTakeOwnershipSpawn(commandArguments)) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
const issueUrl = extractIssueUrl(commandArguments);
|
|
90
|
+
if (issueUrl === null) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
const environ = this.readEnviron(processIdDirectory);
|
|
94
|
+
if (environ === null) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
const token = environ.get(OAUTH_TOKEN_ENVIRON_KEY);
|
|
98
|
+
const sessionId = environ.get(SESSION_ID_ENVIRON_KEY);
|
|
99
|
+
if (token === undefined ||
|
|
100
|
+
token.length === 0 ||
|
|
101
|
+
sessionId === undefined ||
|
|
102
|
+
sessionId.length === 0) {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
return { token, sessionId, issueUrl };
|
|
106
|
+
};
|
|
107
|
+
this.readCommandArguments = (processIdDirectory) => {
|
|
108
|
+
const cmdlinePath = path.join(this.procDirectory, processIdDirectory, 'cmdline');
|
|
109
|
+
let raw;
|
|
110
|
+
try {
|
|
111
|
+
raw = fs.readFileSync(cmdlinePath, 'utf8');
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
return parseCommandLineArguments(raw);
|
|
117
|
+
};
|
|
118
|
+
this.readEnviron = (processIdDirectory) => {
|
|
119
|
+
const environPath = path.join(this.procDirectory, processIdDirectory, 'environ');
|
|
120
|
+
let raw;
|
|
121
|
+
try {
|
|
122
|
+
raw = fs.readFileSync(environPath, 'utf8');
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
const environ = new Map();
|
|
128
|
+
for (const entry of raw.split('\0')) {
|
|
129
|
+
if (entry.length === 0) {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
const separatorIndex = entry.indexOf('=');
|
|
133
|
+
if (separatorIndex <= 0) {
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
const key = entry.slice(0, separatorIndex);
|
|
137
|
+
const value = entry.slice(separatorIndex + 1);
|
|
138
|
+
environ.set(key, value);
|
|
139
|
+
}
|
|
140
|
+
return environ;
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
exports.ProcClaudeInteractiveSessionRepository = ProcClaudeInteractiveSessionRepository;
|
|
145
|
+
//# sourceMappingURL=ProcClaudeInteractiveSessionRepository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProcClaudeInteractiveSessionRepository.js","sourceRoot":"","sources":["../../../src/adapter/repositories/ProcClaudeInteractiveSessionRepository.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAyB;AACzB,2CAA6B;AAM7B,MAAM,sBAAsB,GAAG,OAAO,CAAC;AACvC,MAAM,uBAAuB,GAAG,yBAAyB,CAAC;AAC1D,MAAM,sBAAsB,GAAG,wBAAwB,CAAC;AACxD,MAAM,aAAa,GAAG,QAAQ,CAAC;AAC/B,MAAM,qBAAqB,GAAG,gBAAgB,CAAC;AAE/C,MAAM,UAAU,GAAG,CAAC,KAAa,EAAW,EAAE,CAC5C,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;AAE9D,MAAM,yBAAyB,GAAG,CAAC,OAAe,EAAY,EAAE,CAC9D,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAEhE,MAAM,eAAe,GAAG,CAAC,gBAA0B,EAAiB,EAAE;IACpE,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACpE,IAAI,gBAAgB,CAAC,KAAK,CAAC,KAAK,aAAa,EAAE,CAAC;YAC9C,MAAM,KAAK,GAAG,gBAAgB,CAAC,KAAK,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;YAChD,IAAI,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;gBACtB,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF,MAAM,oBAAoB,GAAG,CAAC,gBAA0B,EAAW,EAAE,CACnE,gBAAgB,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAC,CAAC;AAEhF,MAAa,sCAAsC;IACjD,YACmB,gBAAwB,sBAAsB;QAA9C,kBAAa,GAAb,aAAa,CAAiC;QAGjE,4BAAuB,GAAG,GAA+B,EAAE;YACzD,MAAM,mBAAmB,GAA+B,EAAE,CAAC;YAC3D,KAAK,MAAM,YAAY,IAAI,IAAI,CAAC,wBAAwB,EAAE,EAAE,CAAC;gBAC3D,MAAM,kBAAkB,GAAG,IAAI,CAAC,sBAAsB,CAAC,YAAY,CAAC,CAAC;gBACrE,IAAI,kBAAkB,KAAK,IAAI,EAAE,CAAC;oBAChC,mBAAmB,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;gBAC/C,CAAC;YACH,CAAC;YACD,OAAO,mBAAmB,CAAC;QAC7B,CAAC,CAAC;QAEM,6BAAwB,GAAG,GAAa,EAAE;YAChD,IAAI,OAAiB,CAAC;YACtB,IAAI,CAAC;gBACH,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YAC/C,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QACxD,CAAC,CAAC;QAEM,2BAAsB,GAAG,CAC/B,kBAA0B,EACO,EAAE;YACnC,MAAM,gBAAgB,GAAG,IAAI,CAAC,oBAAoB,CAAC,kBAAkB,CAAC,CAAC;YACvE,IAAI,gBAAgB,KAAK,IAAI,EAAE,CAAC;gBAC9B,OAAO,IAAI,CAAC;YACd,CAAC;YACD,IAAI,oBAAoB,CAAC,gBAAgB,CAAC,EAAE,CAAC;gBAC3C,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,QAAQ,GAAG,eAAe,CAAC,gBAAgB,CAAC,CAAC;YACnD,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;gBACtB,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC;YACrD,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;gBACrB,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;YACnD,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;YACtD,IACE,KAAK,KAAK,SAAS;gBACnB,KAAK,CAAC,MAAM,KAAK,CAAC;gBAClB,SAAS,KAAK,SAAS;gBACvB,SAAS,CAAC,MAAM,KAAK,CAAC,EACtB,CAAC;gBACD,OAAO,IAAI,CAAC;YACd,CAAC;YACD,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;QACxC,CAAC,CAAC;QAEM,yBAAoB,GAAG,CAC7B,kBAA0B,EACT,EAAE;YACnB,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAC3B,IAAI,CAAC,aAAa,EAClB,kBAAkB,EAClB,SAAS,CACV,CAAC;YACF,IAAI,GAAW,CAAC;YAChB,IAAI,CAAC;gBACH,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;YAC7C,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,IAAI,CAAC;YACd,CAAC;YACD,OAAO,yBAAyB,CAAC,GAAG,CAAC,CAAC;QACxC,CAAC,CAAC;QAEM,gBAAW,GAAG,CACpB,kBAA0B,EACE,EAAE;YAC9B,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAC3B,IAAI,CAAC,aAAa,EAClB,kBAAkB,EAClB,SAAS,CACV,CAAC;YACF,IAAI,GAAW,CAAC;YAChB,IAAI,CAAC;gBACH,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;YAC7C,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;YAC1C,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBACpC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBACvB,SAAS;gBACX,CAAC;gBACD,MAAM,cAAc,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBAC1C,IAAI,cAAc,IAAI,CAAC,EAAE,CAAC;oBACxB,SAAS;gBACX,CAAC;gBACD,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;gBAC3C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC;gBAC9C,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YAC1B,CAAC;YACD,OAAO,OAAO,CAAC;QACjB,CAAC,CAAC;IAnGC,CAAC;CAoGL;AAvGD,wFAuGC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InTmuxByHumanSessionTokenCountUseCase = void 0;
|
|
4
|
+
const WorkflowStatus_1 = require("../entities/WorkflowStatus");
|
|
5
|
+
class InTmuxByHumanSessionTokenCountUseCase {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.run = (candidates, interactiveSessions, issues) => {
|
|
8
|
+
const inTmuxByHumanIssueUrls = this.inTmuxByHumanIssueUrls(issues);
|
|
9
|
+
const distinctSessionIdsByToken = this.distinctSessionIdsByToken(interactiveSessions, inTmuxByHumanIssueUrls);
|
|
10
|
+
const counts = candidates.map((candidate) => ({
|
|
11
|
+
name: candidate.name,
|
|
12
|
+
token: candidate.token,
|
|
13
|
+
count: distinctSessionIdsByToken.get(candidate.token)?.size ?? 0,
|
|
14
|
+
}));
|
|
15
|
+
return { counts };
|
|
16
|
+
};
|
|
17
|
+
this.inTmuxByHumanIssueUrls = (issues) => {
|
|
18
|
+
const urls = new Set();
|
|
19
|
+
for (const issue of issues) {
|
|
20
|
+
if (issue.status === WorkflowStatus_1.IN_TMUX_STATUS_NAME && issue.isClosed === false) {
|
|
21
|
+
urls.add(issue.url);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return urls;
|
|
25
|
+
};
|
|
26
|
+
this.distinctSessionIdsByToken = (interactiveSessions, inTmuxByHumanIssueUrls) => {
|
|
27
|
+
const sessionIdsByToken = new Map();
|
|
28
|
+
for (const session of interactiveSessions) {
|
|
29
|
+
if (!inTmuxByHumanIssueUrls.has(session.issueUrl)) {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
const sessionIds = sessionIdsByToken.get(session.token) ?? new Set();
|
|
33
|
+
sessionIds.add(session.sessionId);
|
|
34
|
+
sessionIdsByToken.set(session.token, sessionIds);
|
|
35
|
+
}
|
|
36
|
+
return sessionIdsByToken;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.InTmuxByHumanSessionTokenCountUseCase = InTmuxByHumanSessionTokenCountUseCase;
|
|
41
|
+
//# sourceMappingURL=InTmuxByHumanSessionTokenCountUseCase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InTmuxByHumanSessionTokenCountUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/InTmuxByHumanSessionTokenCountUseCase.ts"],"names":[],"mappings":";;;AACA,+DAAiE;AAcjE,MAAa,qCAAqC;IAAlD;QACE,QAAG,GAAG,CACJ,UAAiC,EACjC,mBAA+C,EAC/C,MAAe,EACuB,EAAE;YACxC,MAAM,sBAAsB,GAAG,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,CAAC;YACnE,MAAM,yBAAyB,GAAG,IAAI,CAAC,yBAAyB,CAC9D,mBAAmB,EACnB,sBAAsB,CACvB,CAAC;YAEF,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;gBAC5C,IAAI,EAAE,SAAS,CAAC,IAAI;gBACpB,KAAK,EAAE,SAAS,CAAC,KAAK;gBACtB,KAAK,EAAE,yBAAyB,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,IAAI,IAAI,CAAC;aACjE,CAAC,CAAC,CAAC;YAEJ,OAAO,EAAE,MAAM,EAAE,CAAC;QACpB,CAAC,CAAC;QAEM,2BAAsB,GAAG,CAAC,MAAe,EAAe,EAAE;YAChE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;YAC/B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,IAAI,KAAK,CAAC,MAAM,KAAK,oCAAmB,IAAI,KAAK,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC;oBACrE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBACtB,CAAC;YACH,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC,CAAC;QAEM,8BAAyB,GAAG,CAClC,mBAA+C,EAC/C,sBAAmC,EACT,EAAE;YAC5B,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAuB,CAAC;YACzD,KAAK,MAAM,OAAO,IAAI,mBAAmB,EAAE,CAAC;gBAC1C,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAClD,SAAS;gBACX,CAAC;gBACD,MAAM,UAAU,GACd,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,IAAI,GAAG,EAAU,CAAC;gBAC5D,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;gBAClC,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;YACnD,CAAC;YACD,OAAO,iBAAiB,CAAC;QAC3B,CAAC,CAAC;IACJ,CAAC;CAAA;AA/CD,sFA+CC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClaudeInteractiveSessionRepository.js","sourceRoot":"","sources":["../../../../src/domain/usecases/adapter-interfaces/ClaudeInteractiveSessionRepository.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "github-issue-tower-defence-management",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.98.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "bin/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
"dependencies": {
|
|
100
100
|
"better-sqlite3": "12.10.0",
|
|
101
101
|
"commander": "^14.0.0",
|
|
102
|
-
"dompurify": "3.4.
|
|
102
|
+
"dompurify": "3.4.11",
|
|
103
103
|
"dotenv": "^17.0.0",
|
|
104
104
|
"googleapis": "^171.4.0",
|
|
105
105
|
"ky": "^2.0.0",
|
|
@@ -43,6 +43,7 @@ import {
|
|
|
43
43
|
} from '../console/consoleProjectResolver';
|
|
44
44
|
import { OauthTokenSelectHandler } from '../handlers/OauthTokenSelectHandler';
|
|
45
45
|
import { LiveSessionOauthTokenSelectHandler } from '../handlers/LiveSessionOauthTokenSelectHandler';
|
|
46
|
+
import { InTmuxByHumanSessionTokenCountHandler } from '../handlers/InTmuxByHumanSessionTokenCountHandler';
|
|
46
47
|
|
|
47
48
|
type StartDaemonOptions = {
|
|
48
49
|
projectUrl?: string;
|
|
@@ -95,6 +96,12 @@ type SelectLiveSessionOauthTokenOptions = {
|
|
|
95
96
|
cacheDir?: string;
|
|
96
97
|
};
|
|
97
98
|
|
|
99
|
+
type CountInTmuxByHumanSessionsPerTokenOptions = {
|
|
100
|
+
configFilePath: string;
|
|
101
|
+
projectUrl?: string;
|
|
102
|
+
tokenListJsonPath?: string;
|
|
103
|
+
};
|
|
104
|
+
|
|
98
105
|
const buildGithubRepositoryParams = (
|
|
99
106
|
localStorageRepository: LocalStorageRepository,
|
|
100
107
|
token: string,
|
|
@@ -795,6 +802,119 @@ program
|
|
|
795
802
|
process.stdout.write(`${output.selectedToken}\n`);
|
|
796
803
|
});
|
|
797
804
|
|
|
805
|
+
program
|
|
806
|
+
.command('countInTmuxByHumanSessionsPerToken')
|
|
807
|
+
.description(
|
|
808
|
+
'Print, per Claude Code OAuth token, the count of live interactive sessions (cl-launched Claude processes carrying CLAUDE_CODE_OAUTH_TOKEN and CLAUDE_CODE_SESSION_ID with a --name <issue-url> argument, excluding Take ownership spawns) whose issue is currently in GitHub Project Status "In Tmux by human". One tab-separated line per token (<tokenName>\\t<count>) is written to stdout; the decision trace is written to stderr. Token values are never printed.',
|
|
809
|
+
)
|
|
810
|
+
.requiredOption(
|
|
811
|
+
'--configFilePath <path>',
|
|
812
|
+
'Path to config file for tower defence management',
|
|
813
|
+
)
|
|
814
|
+
.option('--projectUrl <url>', 'GitHub project URL (optional)')
|
|
815
|
+
.option(
|
|
816
|
+
'--tokenListJsonPath <path>',
|
|
817
|
+
'Path to the JSON array of { name, token } records. Falls back to the claudeCodeOauthTokenListJsonPath config value, then to the CLAUDE_CODE_OAUTH_TOKEN_LIST_JSON_PATH environment variable.',
|
|
818
|
+
)
|
|
819
|
+
.action(async (options: CountInTmuxByHumanSessionsPerTokenOptions) => {
|
|
820
|
+
const token = process.env.GH_TOKEN;
|
|
821
|
+
if (!token) {
|
|
822
|
+
console.error('GH_TOKEN environment variable is required');
|
|
823
|
+
process.exit(1);
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
const configFileValues = loadConfigFile(options.configFilePath);
|
|
827
|
+
|
|
828
|
+
const cliOverrides: ConfigFile = {
|
|
829
|
+
projectUrl: options.projectUrl,
|
|
830
|
+
};
|
|
831
|
+
|
|
832
|
+
const tempProjectUrl =
|
|
833
|
+
cliOverrides.projectUrl ?? configFileValues.projectUrl;
|
|
834
|
+
|
|
835
|
+
let readmeOverrides: ConfigFile = {};
|
|
836
|
+
if (tempProjectUrl) {
|
|
837
|
+
const readme = await fetchProjectReadme(tempProjectUrl, token);
|
|
838
|
+
if (readme) {
|
|
839
|
+
readmeOverrides = parseProjectReadmeConfig(readme, tempProjectUrl);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
const config = mergeConfigs(
|
|
844
|
+
configFileValues,
|
|
845
|
+
cliOverrides,
|
|
846
|
+
readmeOverrides,
|
|
847
|
+
);
|
|
848
|
+
|
|
849
|
+
const projectUrl = config.projectUrl;
|
|
850
|
+
if (!projectUrl) {
|
|
851
|
+
console.error(
|
|
852
|
+
'projectUrl is required. Provide via --projectUrl, config file, or project README.',
|
|
853
|
+
);
|
|
854
|
+
process.exit(1);
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
const projectName = config.projectName ?? 'default';
|
|
858
|
+
const localStorageRepository = new LocalStorageRepository();
|
|
859
|
+
const cachePath = `./tmp/cache/${projectName}`;
|
|
860
|
+
const localStorageCacheRepository = new LocalStorageCacheRepository(
|
|
861
|
+
localStorageRepository,
|
|
862
|
+
cachePath,
|
|
863
|
+
);
|
|
864
|
+
const githubRepositoryParams = buildGithubRepositoryParams(
|
|
865
|
+
localStorageRepository,
|
|
866
|
+
token,
|
|
867
|
+
);
|
|
868
|
+
const projectRepository = new GraphqlProjectRepository(
|
|
869
|
+
...githubRepositoryParams,
|
|
870
|
+
);
|
|
871
|
+
const apiV3IssueRepository = new ApiV3IssueRepository(
|
|
872
|
+
...githubRepositoryParams,
|
|
873
|
+
);
|
|
874
|
+
const restIssueRepository = new RestIssueRepository(
|
|
875
|
+
...githubRepositoryParams,
|
|
876
|
+
);
|
|
877
|
+
const graphqlProjectItemRepository = new GraphqlProjectItemRepository(
|
|
878
|
+
...githubRepositoryParams,
|
|
879
|
+
);
|
|
880
|
+
const issueRepository = new ApiV3CheerioRestIssueRepository(
|
|
881
|
+
apiV3IssueRepository,
|
|
882
|
+
restIssueRepository,
|
|
883
|
+
graphqlProjectItemRepository,
|
|
884
|
+
localStorageCacheRepository,
|
|
885
|
+
...githubRepositoryParams,
|
|
886
|
+
);
|
|
887
|
+
|
|
888
|
+
const projectId = await projectRepository.findProjectIdByUrl(projectUrl);
|
|
889
|
+
if (!projectId) {
|
|
890
|
+
console.error(`No project found for projectUrl ${projectUrl}`);
|
|
891
|
+
process.exit(1);
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
const allowIssueCacheMinutes = config.allowIssueCacheMinutes ?? 10;
|
|
895
|
+
const { issues } = await issueRepository.getAllIssues(
|
|
896
|
+
projectId,
|
|
897
|
+
allowIssueCacheMinutes,
|
|
898
|
+
);
|
|
899
|
+
|
|
900
|
+
const handler = new InTmuxByHumanSessionTokenCountHandler();
|
|
901
|
+
const output = handler.handle({
|
|
902
|
+
tokenListJsonPath:
|
|
903
|
+
options.tokenListJsonPath ??
|
|
904
|
+
config.claudeCodeOauthTokenListJsonPath ??
|
|
905
|
+
null,
|
|
906
|
+
issues,
|
|
907
|
+
});
|
|
908
|
+
|
|
909
|
+
for (const line of output.diagnostics) {
|
|
910
|
+
console.error(line);
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
for (const line of output.lines) {
|
|
914
|
+
process.stdout.write(`${line}\n`);
|
|
915
|
+
}
|
|
916
|
+
});
|
|
917
|
+
|
|
798
918
|
/* istanbul ignore next */
|
|
799
919
|
if (process.argv && require.main === module) {
|
|
800
920
|
program.parse(process.argv);
|