panopticon-cli 0.4.10 → 0.4.12
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/dist/{chunk-NRPHRN6M.js → chunk-WLL3UEYI.js} +40 -14
- package/dist/chunk-WLL3UEYI.js.map +1 -0
- package/dist/cli/index.js +1 -1
- package/dist/dashboard/public/assets/index-Bp7DyPLO.css +32 -0
- package/dist/dashboard/public/assets/{index-GwTde56u.js → index-Bwu9d0w1.js} +54 -54
- package/dist/dashboard/public/index.html +2 -2
- package/dist/dashboard/server.js +202 -53
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-NRPHRN6M.js.map +0 -1
- package/dist/dashboard/public/assets/index-iqMjcW09.css +0 -32
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
}
|
|
18
18
|
})();
|
|
19
19
|
</script>
|
|
20
|
-
<script type="module" crossorigin src="/assets/index-
|
|
21
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
20
|
+
<script type="module" crossorigin src="/assets/index-Bwu9d0w1.js"></script>
|
|
21
|
+
<link rel="stylesheet" crossorigin href="/assets/index-Bp7DyPLO.css">
|
|
22
22
|
</head>
|
|
23
23
|
<body class="bg-surface text-content transition-colors duration-150">
|
|
24
24
|
<div id="root"></div>
|
package/dist/dashboard/server.js
CHANGED
|
@@ -51114,6 +51114,10 @@ var init_shadow_state = __esm({
|
|
|
51114
51114
|
});
|
|
51115
51115
|
|
|
51116
51116
|
// ../../lib/tracker/rally-api.ts
|
|
51117
|
+
var rally_api_exports = {};
|
|
51118
|
+
__export(rally_api_exports, {
|
|
51119
|
+
RallyRestApi: () => RallyRestApi
|
|
51120
|
+
});
|
|
51117
51121
|
var RallyRestApi;
|
|
51118
51122
|
var init_rally_api = __esm({
|
|
51119
51123
|
"../../lib/tracker/rally-api.ts"() {
|
|
@@ -51170,7 +51174,12 @@ var init_rally_api = __esm({
|
|
|
51170
51174
|
}
|
|
51171
51175
|
const result = await response.json();
|
|
51172
51176
|
if (result.QueryResult.Errors && result.QueryResult.Errors.length > 0) {
|
|
51173
|
-
|
|
51177
|
+
const errorDetail = result.QueryResult.Errors.join(", ");
|
|
51178
|
+
const queryDetail = config2.query ? ` (Query: ${config2.query})` : "";
|
|
51179
|
+
if (process.env.DEBUG?.includes("rally")) {
|
|
51180
|
+
console.error("[Rally WSAPI] Query failed:", { query: config2.query, errors: result.QueryResult.Errors });
|
|
51181
|
+
}
|
|
51182
|
+
throw new Error(`Rally API query failed: ${errorDetail}${queryDetail}`);
|
|
51174
51183
|
}
|
|
51175
51184
|
return result;
|
|
51176
51185
|
}
|
|
@@ -51316,6 +51325,11 @@ var init_rally = __esm({
|
|
|
51316
51325
|
this.project = config2.project;
|
|
51317
51326
|
}
|
|
51318
51327
|
async listIssues(filters) {
|
|
51328
|
+
const queryString = this.buildQueryString(filters);
|
|
51329
|
+
if (process.env.DEBUG?.includes("rally")) {
|
|
51330
|
+
console.debug("[Rally] Query filters:", JSON.stringify(filters));
|
|
51331
|
+
console.debug("[Rally] Generated query:", queryString);
|
|
51332
|
+
}
|
|
51319
51333
|
const query = {
|
|
51320
51334
|
type: "artifact",
|
|
51321
51335
|
// Query all artifact types
|
|
@@ -51336,7 +51350,7 @@ var init_rally = __esm({
|
|
|
51336
51350
|
"_type"
|
|
51337
51351
|
],
|
|
51338
51352
|
limit: filters?.limit ?? 50,
|
|
51339
|
-
query:
|
|
51353
|
+
query: queryString
|
|
51340
51354
|
};
|
|
51341
51355
|
if (this.workspace) {
|
|
51342
51356
|
query.workspace = this.workspace;
|
|
@@ -51537,6 +51551,17 @@ var init_rally = __esm({
|
|
|
51537
51551
|
await this.addComment(issueId, `Linked Pull Request: ${prUrl}`);
|
|
51538
51552
|
}
|
|
51539
51553
|
// Private helper methods
|
|
51554
|
+
/**
|
|
51555
|
+
* Build a Rally WSAPI query string from issue filters.
|
|
51556
|
+
*
|
|
51557
|
+
* Rally WSAPI v2.0 requires the entire compound query expression to be wrapped
|
|
51558
|
+
* in outer parentheses when multiple conditions are joined with AND/OR.
|
|
51559
|
+
* Without the outer parens, the WSAPI parser fails with:
|
|
51560
|
+
* "Could not parse: Error parsing expression -- expected ")" but saw "AND" instead."
|
|
51561
|
+
*
|
|
51562
|
+
* Valid: (((ScheduleState != "Completed") AND (State != "Closed")) AND (Owner.Name contains "John"))
|
|
51563
|
+
* Invalid: ((ScheduleState != "Completed") AND (State != "Closed")) AND (Owner.Name contains "John")
|
|
51564
|
+
*/
|
|
51540
51565
|
buildQueryString(filters) {
|
|
51541
51566
|
const conditions = [];
|
|
51542
51567
|
if (filters?.state && !filters.includeClosed) {
|
|
@@ -51544,7 +51569,7 @@ var init_rally = __esm({
|
|
|
51544
51569
|
conditions.push(`((ScheduleState = "${rallyState}") OR (State = "${rallyState}"))`);
|
|
51545
51570
|
}
|
|
51546
51571
|
if (!filters?.includeClosed) {
|
|
51547
|
-
conditions.push('((ScheduleState != "Completed") AND (ScheduleState != "Accepted") AND (State != "Closed"))');
|
|
51572
|
+
conditions.push('(((ScheduleState != "Completed") AND (ScheduleState != "Accepted")) AND (State != "Closed"))');
|
|
51548
51573
|
}
|
|
51549
51574
|
if (filters?.assignee) {
|
|
51550
51575
|
conditions.push(`(Owner.Name contains "${filters.assignee}")`);
|
|
@@ -51553,12 +51578,13 @@ var init_rally = __esm({
|
|
|
51553
51578
|
const labelConditions = filters.labels.map(
|
|
51554
51579
|
(label) => `(Tags.Name contains "${label}")`
|
|
51555
51580
|
);
|
|
51556
|
-
|
|
51581
|
+
const labelExpr = labelConditions.reduce((acc, cond) => acc ? `(${acc} AND ${cond})` : cond, "");
|
|
51582
|
+
conditions.push(labelExpr);
|
|
51557
51583
|
}
|
|
51558
51584
|
if (filters?.query) {
|
|
51559
51585
|
conditions.push(`((Name contains "${filters.query}") OR (Description contains "${filters.query}"))`);
|
|
51560
51586
|
}
|
|
51561
|
-
return conditions.
|
|
51587
|
+
return conditions.reduce((acc, cond) => acc ? `(${acc} AND ${cond})` : cond, "");
|
|
51562
51588
|
}
|
|
51563
51589
|
normalizeIssue(rallyArtifact) {
|
|
51564
51590
|
const stateValue = rallyArtifact.ScheduleState || rallyArtifact.State || "Defined";
|
|
@@ -84863,6 +84889,12 @@ import { readFileSync as readFileSync2, existsSync as existsSync3 } from "fs";
|
|
|
84863
84889
|
import { join as join3 } from "path";
|
|
84864
84890
|
import { homedir as homedir3 } from "os";
|
|
84865
84891
|
function getLinearApiKey() {
|
|
84892
|
+
try {
|
|
84893
|
+
const yamlConfig = loadConfig();
|
|
84894
|
+
if (yamlConfig.trackerKeys.linear)
|
|
84895
|
+
return yamlConfig.trackerKeys.linear;
|
|
84896
|
+
} catch {
|
|
84897
|
+
}
|
|
84866
84898
|
const envFile = join3(homedir3(), ".panopticon.env");
|
|
84867
84899
|
if (existsSync3(envFile)) {
|
|
84868
84900
|
const content = readFileSync2(envFile, "utf-8");
|
|
@@ -84870,27 +84902,27 @@ function getLinearApiKey() {
|
|
|
84870
84902
|
if (match)
|
|
84871
84903
|
return match[1].trim();
|
|
84872
84904
|
}
|
|
84873
|
-
|
|
84874
|
-
return process.env.LINEAR_API_KEY;
|
|
84875
|
-
try {
|
|
84876
|
-
const yamlConfig = loadConfig();
|
|
84877
|
-
if (yamlConfig.trackerKeys.linear)
|
|
84878
|
-
return yamlConfig.trackerKeys.linear;
|
|
84879
|
-
} catch {
|
|
84880
|
-
}
|
|
84881
|
-
return null;
|
|
84905
|
+
return process.env.LINEAR_API_KEY || null;
|
|
84882
84906
|
}
|
|
84883
84907
|
function getRallyConfig() {
|
|
84884
|
-
const envFile = join3(homedir3(), ".panopticon.env");
|
|
84885
84908
|
let apiKey;
|
|
84886
84909
|
let server2;
|
|
84887
84910
|
let workspace;
|
|
84888
84911
|
let project;
|
|
84912
|
+
try {
|
|
84913
|
+
const yamlConfig = loadConfig();
|
|
84914
|
+
if (yamlConfig.trackerKeys.rally)
|
|
84915
|
+
apiKey = yamlConfig.trackerKeys.rally;
|
|
84916
|
+
} catch {
|
|
84917
|
+
}
|
|
84918
|
+
const envFile = join3(homedir3(), ".panopticon.env");
|
|
84889
84919
|
if (existsSync3(envFile)) {
|
|
84890
84920
|
const content = readFileSync2(envFile, "utf-8");
|
|
84891
|
-
|
|
84892
|
-
|
|
84893
|
-
|
|
84921
|
+
if (!apiKey) {
|
|
84922
|
+
const apiKeyMatch = content.match(/RALLY_API_KEY=(.+)/);
|
|
84923
|
+
if (apiKeyMatch)
|
|
84924
|
+
apiKey = apiKeyMatch[1].trim();
|
|
84925
|
+
}
|
|
84894
84926
|
const serverMatch = content.match(/RALLY_SERVER=(.+)/);
|
|
84895
84927
|
server2 = serverMatch?.[1].trim();
|
|
84896
84928
|
const workspaceMatch = content.match(/RALLY_WORKSPACE=(.+)/);
|
|
@@ -84900,27 +84932,41 @@ function getRallyConfig() {
|
|
|
84900
84932
|
}
|
|
84901
84933
|
if (!apiKey)
|
|
84902
84934
|
apiKey = process.env.RALLY_API_KEY;
|
|
84903
|
-
if (!apiKey) {
|
|
84904
|
-
try {
|
|
84905
|
-
const yamlConfig = loadConfig();
|
|
84906
|
-
if (yamlConfig.trackerKeys.rally)
|
|
84907
|
-
apiKey = yamlConfig.trackerKeys.rally;
|
|
84908
|
-
} catch {
|
|
84909
|
-
}
|
|
84910
|
-
}
|
|
84911
84935
|
if (!apiKey)
|
|
84912
84936
|
return null;
|
|
84913
84937
|
return { apiKey, server: server2, workspace, project };
|
|
84914
84938
|
}
|
|
84939
|
+
function validateRallyConfig(config2) {
|
|
84940
|
+
const warnings = [];
|
|
84941
|
+
const errors = [];
|
|
84942
|
+
if (!config2.apiKey) {
|
|
84943
|
+
errors.push("RALLY_API_KEY is required");
|
|
84944
|
+
}
|
|
84945
|
+
if (!config2.workspace) {
|
|
84946
|
+
warnings.push("RALLY_WORKSPACE not configured - queries may return unexpected results");
|
|
84947
|
+
}
|
|
84948
|
+
if (!config2.project) {
|
|
84949
|
+
warnings.push("RALLY_PROJECT not configured - queries will search all projects");
|
|
84950
|
+
}
|
|
84951
|
+
return { valid: errors.length === 0, warnings, errors };
|
|
84952
|
+
}
|
|
84915
84953
|
function getGitHubConfig() {
|
|
84916
|
-
const envFile = join3(homedir3(), ".panopticon.env");
|
|
84917
84954
|
let token;
|
|
84918
84955
|
let repos = [];
|
|
84956
|
+
try {
|
|
84957
|
+
const yamlConfig = loadConfig();
|
|
84958
|
+
if (yamlConfig.trackerKeys.github)
|
|
84959
|
+
token = yamlConfig.trackerKeys.github;
|
|
84960
|
+
} catch {
|
|
84961
|
+
}
|
|
84962
|
+
const envFile = join3(homedir3(), ".panopticon.env");
|
|
84919
84963
|
if (existsSync3(envFile)) {
|
|
84920
84964
|
const content = readFileSync2(envFile, "utf-8");
|
|
84921
|
-
|
|
84922
|
-
|
|
84923
|
-
|
|
84965
|
+
if (!token) {
|
|
84966
|
+
const tokenMatch = content.match(/GITHUB_TOKEN=(.+)/);
|
|
84967
|
+
if (tokenMatch)
|
|
84968
|
+
token = tokenMatch[1].trim();
|
|
84969
|
+
}
|
|
84924
84970
|
const reposMatch = content.match(/GITHUB_REPOS=(.+)/);
|
|
84925
84971
|
if (reposMatch) {
|
|
84926
84972
|
repos = reposMatch[1].trim().split(",").map((r) => {
|
|
@@ -84932,14 +84978,6 @@ function getGitHubConfig() {
|
|
|
84932
84978
|
}
|
|
84933
84979
|
if (!token)
|
|
84934
84980
|
token = process.env.GITHUB_TOKEN;
|
|
84935
|
-
if (!token) {
|
|
84936
|
-
try {
|
|
84937
|
-
const yamlConfig = loadConfig();
|
|
84938
|
-
if (yamlConfig.trackerKeys.github)
|
|
84939
|
-
token = yamlConfig.trackerKeys.github;
|
|
84940
|
-
} catch {
|
|
84941
|
-
}
|
|
84942
|
-
}
|
|
84943
84981
|
if (!token || repos.length === 0)
|
|
84944
84982
|
return null;
|
|
84945
84983
|
return { token, repos };
|
|
@@ -85527,6 +85565,12 @@ var IssueDataService = class {
|
|
|
85527
85565
|
this.trackers.rally.lastFetchedIssues = [];
|
|
85528
85566
|
return;
|
|
85529
85567
|
}
|
|
85568
|
+
if (!this.trackers.rally.lastFetchedAt) {
|
|
85569
|
+
const validation = validateRallyConfig(config2);
|
|
85570
|
+
if (validation.warnings.length > 0) {
|
|
85571
|
+
console.warn("[Rally] Configuration warnings:", validation.warnings.join("; "));
|
|
85572
|
+
}
|
|
85573
|
+
}
|
|
85530
85574
|
if (!this.cache.isStale("rally", "issues") && this.trackers.rally.lastFetchedIssues.length > 0) {
|
|
85531
85575
|
return;
|
|
85532
85576
|
}
|
|
@@ -85580,8 +85624,9 @@ var IssueDataService = class {
|
|
|
85580
85624
|
this.pushMeta();
|
|
85581
85625
|
}
|
|
85582
85626
|
} catch (err) {
|
|
85583
|
-
|
|
85584
|
-
|
|
85627
|
+
const errorMsg = err.message?.includes("Could not parse") ? `${err.message} - Check Rally workspace/project configuration. Enable DEBUG=rally for query details.` : err.message;
|
|
85628
|
+
console.error("[IssueDataService] Rally poll error:", errorMsg);
|
|
85629
|
+
this.trackers.rally.lastError = errorMsg;
|
|
85585
85630
|
}
|
|
85586
85631
|
}
|
|
85587
85632
|
};
|
|
@@ -90078,11 +90123,6 @@ function getReviewStatus(issueId, filePath = DEFAULT_STATUS_FILE) {
|
|
|
90078
90123
|
const statuses = loadReviewStatuses(filePath);
|
|
90079
90124
|
return statuses[issueId] || null;
|
|
90080
90125
|
}
|
|
90081
|
-
function clearReviewStatus(issueId, filePath = DEFAULT_STATUS_FILE) {
|
|
90082
|
-
const statuses = loadReviewStatuses(filePath);
|
|
90083
|
-
delete statuses[issueId];
|
|
90084
|
-
saveReviewStatuses(statuses, filePath);
|
|
90085
|
-
}
|
|
90086
90126
|
|
|
90087
90127
|
// ../../lib/remote/index.ts
|
|
90088
90128
|
init_exe_provider();
|
|
@@ -92100,6 +92140,41 @@ app.get("/api/tracker-status", (_req, res) => {
|
|
|
92100
92140
|
res.status(500).json({ error: "Failed to check tracker status: " + error.message });
|
|
92101
92141
|
}
|
|
92102
92142
|
});
|
|
92143
|
+
app.post("/api/rally/validate", async (req, res) => {
|
|
92144
|
+
try {
|
|
92145
|
+
const { apiKey, server: server2, workspace, project } = req.body;
|
|
92146
|
+
if (!apiKey) {
|
|
92147
|
+
res.status(400).json({ valid: false, error: "API key is required" });
|
|
92148
|
+
return;
|
|
92149
|
+
}
|
|
92150
|
+
const { RallyRestApi: RallyRestApi2 } = await Promise.resolve().then(() => (init_rally_api(), rally_api_exports));
|
|
92151
|
+
const api = new RallyRestApi2({
|
|
92152
|
+
apiKey,
|
|
92153
|
+
server: server2 || "https://rally1.rallydev.com"
|
|
92154
|
+
});
|
|
92155
|
+
const result = await api.query({
|
|
92156
|
+
type: "artifact",
|
|
92157
|
+
fetch: ["FormattedID"],
|
|
92158
|
+
query: '((State = "Open"))',
|
|
92159
|
+
limit: 1,
|
|
92160
|
+
workspace,
|
|
92161
|
+
project
|
|
92162
|
+
});
|
|
92163
|
+
res.json({
|
|
92164
|
+
valid: true,
|
|
92165
|
+
message: "Rally connection successful",
|
|
92166
|
+
testQueryResult: `Found ${result.QueryResult.TotalResultCount} artifacts`
|
|
92167
|
+
});
|
|
92168
|
+
} catch (err) {
|
|
92169
|
+
const isAuthError = err.message?.includes("Unauthorized") || err.message?.includes("401");
|
|
92170
|
+
const isParseError = err.message?.includes("Could not parse");
|
|
92171
|
+
res.status(400).json({
|
|
92172
|
+
valid: false,
|
|
92173
|
+
error: err.message,
|
|
92174
|
+
errorType: isAuthError ? "auth" : isParseError ? "query" : "network"
|
|
92175
|
+
});
|
|
92176
|
+
}
|
|
92177
|
+
});
|
|
92103
92178
|
app.get("/api/cloister/config", (_req, res) => {
|
|
92104
92179
|
try {
|
|
92105
92180
|
const config2 = loadCloisterConfig();
|
|
@@ -94731,7 +94806,6 @@ app.post("/api/workspaces/:issueId/merge", async (req, res) => {
|
|
|
94731
94806
|
);
|
|
94732
94807
|
console.log(`[merge] PR merge output: ${mergeOutput}`);
|
|
94733
94808
|
setReviewStatus2(issueId, { mergeStatus: "merged", readyForMerge: false });
|
|
94734
|
-
clearReviewStatus(issueId);
|
|
94735
94809
|
completePendingOperation(issueId, null);
|
|
94736
94810
|
await closeIssueAfterMerge(issueId);
|
|
94737
94811
|
return res.json({
|
|
@@ -94770,7 +94844,7 @@ app.post("/api/workspaces/:issueId/merge", async (req, res) => {
|
|
|
94770
94844
|
);
|
|
94771
94845
|
if (mergeResult.success && mergeResult.testsStatus === "PASS") {
|
|
94772
94846
|
console.log(`[merge] Successfully merged ${issueId}`);
|
|
94773
|
-
|
|
94847
|
+
setReviewStatus2(issueId, { mergeStatus: "merged", readyForMerge: false });
|
|
94774
94848
|
completePendingOperation(issueId, null);
|
|
94775
94849
|
await closeIssueAfterMerge(issueId);
|
|
94776
94850
|
return res.json({
|
|
@@ -94780,7 +94854,7 @@ app.post("/api/workspaces/:issueId/merge", async (req, res) => {
|
|
|
94780
94854
|
});
|
|
94781
94855
|
} else if (mergeResult.success) {
|
|
94782
94856
|
console.log(`[merge] Merged ${issueId} (tests: ${mergeResult.testsStatus})`);
|
|
94783
|
-
|
|
94857
|
+
setReviewStatus2(issueId, { mergeStatus: "merged", readyForMerge: false });
|
|
94784
94858
|
completePendingOperation(issueId, null);
|
|
94785
94859
|
await closeIssueAfterMerge(issueId);
|
|
94786
94860
|
return res.json({
|
|
@@ -98791,6 +98865,28 @@ ${stateMd}`
|
|
|
98791
98865
|
}
|
|
98792
98866
|
const centralStatus = getReviewStatus(issueId.toUpperCase());
|
|
98793
98867
|
if (centralStatus?.history && centralStatus.history.length > 0) {
|
|
98868
|
+
const tasksDir = join43(homedir20(), ".panopticon", "specialists", "tasks");
|
|
98869
|
+
const taskFilesByType = { review: [], test: [], merge: [] };
|
|
98870
|
+
try {
|
|
98871
|
+
if (existsSync44(tasksDir)) {
|
|
98872
|
+
const taskFiles = readdirSync17(tasksDir).filter((f) => f.endsWith(".md"));
|
|
98873
|
+
for (const f of taskFiles) {
|
|
98874
|
+
const content = readFileSync37(join43(tasksDir, f), "utf-8");
|
|
98875
|
+
if (content.includes(issueId.toUpperCase()) || content.includes(issueId)) {
|
|
98876
|
+
if (f.startsWith("review-agent"))
|
|
98877
|
+
taskFilesByType.review.push(f);
|
|
98878
|
+
else if (f.startsWith("test-agent"))
|
|
98879
|
+
taskFilesByType.test.push(f);
|
|
98880
|
+
else if (f.startsWith("merge-agent"))
|
|
98881
|
+
taskFilesByType.merge.push(f);
|
|
98882
|
+
}
|
|
98883
|
+
}
|
|
98884
|
+
for (const type2 of Object.keys(taskFilesByType)) {
|
|
98885
|
+
taskFilesByType[type2].sort();
|
|
98886
|
+
}
|
|
98887
|
+
}
|
|
98888
|
+
} catch {
|
|
98889
|
+
}
|
|
98794
98890
|
const typeMap = { review: "review", test: "test", merge: "merge" };
|
|
98795
98891
|
let currentSection = null;
|
|
98796
98892
|
const specialistSections = [];
|
|
@@ -98815,11 +98911,48 @@ ${stateMd}`
|
|
|
98815
98911
|
}
|
|
98816
98912
|
if (currentSection)
|
|
98817
98913
|
specialistSections.push(currentSection);
|
|
98914
|
+
const taskFileIndex = { review: 0, test: 0, merge: 0 };
|
|
98818
98915
|
for (const ss of specialistSections) {
|
|
98819
98916
|
const duration = ss.startedAt && ss.endedAt ? Math.floor((new Date(ss.endedAt).getTime() - new Date(ss.startedAt).getTime()) / 1e3) : null;
|
|
98820
|
-
const
|
|
98821
|
-
|
|
98822
|
-
|
|
98917
|
+
const transcriptParts = [];
|
|
98918
|
+
const statusLabel = ss.status === "completed" ? "PASSED" : ss.status === "running" ? "IN PROGRESS..." : ss.status.toUpperCase();
|
|
98919
|
+
transcriptParts.push(`${ss.type.toUpperCase()} ${statusLabel}`);
|
|
98920
|
+
const taskFiles = taskFilesByType[ss.type] || [];
|
|
98921
|
+
const taskIdx = taskFileIndex[ss.type] || 0;
|
|
98922
|
+
if (taskIdx < taskFiles.length) {
|
|
98923
|
+
try {
|
|
98924
|
+
const taskContent = readFileSync37(join43(tasksDir, taskFiles[taskIdx]), "utf-8");
|
|
98925
|
+
const taskLines = taskContent.split("\n");
|
|
98926
|
+
const meaningfulLines = taskLines.filter(
|
|
98927
|
+
(l) => !l.startsWith("```") && !l.startsWith("# EXECUTE") && !l.startsWith("\u26A0\uFE0F")
|
|
98928
|
+
);
|
|
98929
|
+
transcriptParts.push(`
|
|
98930
|
+
--- Task ---
|
|
98931
|
+
${meaningfulLines.slice(0, 5).join("\n")}`);
|
|
98932
|
+
} catch {
|
|
98933
|
+
}
|
|
98934
|
+
taskFileIndex[ss.type] = taskIdx + 1;
|
|
98935
|
+
}
|
|
98936
|
+
if (ss.status === "running") {
|
|
98937
|
+
const tmuxName = `specialist-${ss.type === "review" ? "review-agent" : ss.type === "test" ? "test-agent" : "merge-agent"}`;
|
|
98938
|
+
try {
|
|
98939
|
+
const { stdout } = await execAsync15(
|
|
98940
|
+
`tmux capture-pane -t ${tmuxName} -p -S -100 2>/dev/null || echo ""`,
|
|
98941
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
98942
|
+
);
|
|
98943
|
+
if (stdout.trim()) {
|
|
98944
|
+
transcriptParts.push(`
|
|
98945
|
+
--- Live Output ---
|
|
98946
|
+
${stdout.trim()}`);
|
|
98947
|
+
}
|
|
98948
|
+
} catch {
|
|
98949
|
+
}
|
|
98950
|
+
}
|
|
98951
|
+
if (ss.notes) {
|
|
98952
|
+
transcriptParts.push(`
|
|
98953
|
+
--- Results ---
|
|
98954
|
+
${ss.notes}`);
|
|
98955
|
+
}
|
|
98823
98956
|
sections.push({
|
|
98824
98957
|
type: ss.type,
|
|
98825
98958
|
sessionId: `specialist-${ss.type}-${ss.startedAt}`,
|
|
@@ -98827,7 +98960,7 @@ ${ss.notes}` : `${ss.type.toUpperCase()} ${ss.status === "completed" ? "PASSED"
|
|
|
98827
98960
|
startedAt: ss.startedAt,
|
|
98828
98961
|
duration,
|
|
98829
98962
|
status: ss.status,
|
|
98830
|
-
transcript
|
|
98963
|
+
transcript: transcriptParts.join("\n")
|
|
98831
98964
|
});
|
|
98832
98965
|
}
|
|
98833
98966
|
}
|
|
@@ -98838,7 +98971,23 @@ ${ss.notes}` : `${ss.type.toUpperCase()} ${ss.status === "completed" ? "PASSED"
|
|
|
98838
98971
|
return -1;
|
|
98839
98972
|
return new Date(a.startedAt).getTime() - new Date(b.startedAt).getTime();
|
|
98840
98973
|
});
|
|
98841
|
-
|
|
98974
|
+
let costByStage = {};
|
|
98975
|
+
let totalCost = 0;
|
|
98976
|
+
try {
|
|
98977
|
+
syncCache();
|
|
98978
|
+
const issueData = getCostsForIssue(issueId.toUpperCase());
|
|
98979
|
+
if (issueData) {
|
|
98980
|
+
totalCost = issueData.totalCost;
|
|
98981
|
+
costByStage = Object.fromEntries(
|
|
98982
|
+
Object.entries(issueData.stages || {}).map(([stage, stats]) => [
|
|
98983
|
+
stage,
|
|
98984
|
+
{ cost: stats.cost, tokens: stats.tokens }
|
|
98985
|
+
])
|
|
98986
|
+
);
|
|
98987
|
+
}
|
|
98988
|
+
} catch {
|
|
98989
|
+
}
|
|
98990
|
+
res.json({ issueId, sections, costByStage, totalCost });
|
|
98842
98991
|
} catch (error) {
|
|
98843
98992
|
res.status(500).json({ error: "Failed to fetch activity: " + error.message });
|
|
98844
98993
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -466,7 +466,8 @@ interface TrackerConfig {
|
|
|
466
466
|
project?: string;
|
|
467
467
|
}
|
|
468
468
|
/**
|
|
469
|
-
* Create a tracker instance from configuration
|
|
469
|
+
* Create a tracker instance from configuration.
|
|
470
|
+
* Priority: config.yaml (Settings) > environment variable > custom env var name
|
|
470
471
|
*/
|
|
471
472
|
declare function createTracker(config: TrackerConfig): IssueTracker;
|
|
472
473
|
/**
|
package/dist/index.js
CHANGED