panopticon-cli 0.4.27 → 0.4.28
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.
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
}
|
|
18
18
|
})();
|
|
19
19
|
</script>
|
|
20
|
-
<script type="module" crossorigin src="/assets/index-
|
|
20
|
+
<script type="module" crossorigin src="/assets/index-GYQaqwVS.js"></script>
|
|
21
21
|
<link rel="stylesheet" crossorigin href="/assets/index--VPaQ2VU.css">
|
|
22
22
|
</head>
|
|
23
23
|
<body class="bg-surface text-content transition-colors duration-150">
|
package/dist/dashboard/server.js
CHANGED
|
@@ -99636,20 +99636,57 @@ app.post("/api/mission-control/planning/:issueId/status-review", async (req, res
|
|
|
99636
99636
|
const statePath = join43(planningDir, "STATE.md");
|
|
99637
99637
|
const prd = existsSync44(prdPath) ? readFileSync37(prdPath, "utf-8") : null;
|
|
99638
99638
|
const state = existsSync44(statePath) ? readFileSync37(statePath, "utf-8") : null;
|
|
99639
|
-
const
|
|
99640
|
-
|
|
99641
|
-
|
|
99642
|
-
|
|
99643
|
-
|
|
99644
|
-
|
|
99645
|
-
|
|
99639
|
+
const readPlanningSubdir = (subdir, limit = 5, maxPerFile = 2e3) => {
|
|
99640
|
+
const dirPath = join43(planningDir, subdir);
|
|
99641
|
+
if (!existsSync44(dirPath))
|
|
99642
|
+
return "";
|
|
99643
|
+
const files = readdirSync17(dirPath).filter((f) => f.endsWith(".md") || f.endsWith(".txt"));
|
|
99644
|
+
return files.slice(0, limit).map((file) => {
|
|
99645
|
+
const content = readFileSync37(join43(dirPath, file), "utf-8");
|
|
99646
|
+
return `
|
|
99646
99647
|
### ${file}
|
|
99647
|
-
${content.slice(0,
|
|
99648
|
+
${content.slice(0, maxPerFile)}
|
|
99649
|
+
`;
|
|
99650
|
+
}).join("");
|
|
99651
|
+
};
|
|
99652
|
+
const discussionsContent = readPlanningSubdir("discussions");
|
|
99653
|
+
const transcriptsContent = readPlanningSubdir("transcripts", 5, 3e3);
|
|
99654
|
+
const notesContent = readPlanningSubdir("notes");
|
|
99655
|
+
let issueContext = "";
|
|
99656
|
+
try {
|
|
99657
|
+
const allIssues = issueDataService.getIssues();
|
|
99658
|
+
const issue = allIssues.find(
|
|
99659
|
+
(i) => i.identifier === issueId || i.identifier?.toLowerCase() === issueId.toLowerCase()
|
|
99660
|
+
);
|
|
99661
|
+
if (issue) {
|
|
99662
|
+
issueContext = `- **Title**: ${issue.title}
|
|
99663
|
+
- **Status**: ${issue.rawTrackerState || issue.status}
|
|
99664
|
+
- **Assignee**: ${issue.assignee?.name || "Unassigned"}
|
|
99665
|
+
- **Source**: ${issue.source}`;
|
|
99666
|
+
if (issue.labels?.length)
|
|
99667
|
+
issueContext += `
|
|
99668
|
+
- **Labels**: ${issue.labels.join(", ")}`;
|
|
99669
|
+
const children = allIssues.filter((i) => i.parentRef === issueId);
|
|
99670
|
+
if (children.length > 0) {
|
|
99671
|
+
const done = children.filter((c) => c.status === "Done").length;
|
|
99672
|
+
const inProgress = children.filter((c) => c.status === "In Progress").length;
|
|
99673
|
+
issueContext += `
|
|
99674
|
+
- **Child Stories**: ${children.length} total, ${done} done, ${inProgress} in progress`;
|
|
99675
|
+
issueContext += `
|
|
99676
|
+
|
|
99677
|
+
**Story Breakdown:**
|
|
99678
|
+
`;
|
|
99679
|
+
for (const child of children.slice(0, 20)) {
|
|
99680
|
+
issueContext += ` - ${child.identifier}: ${child.title} [${child.rawTrackerState || child.status}]
|
|
99648
99681
|
`;
|
|
99682
|
+
}
|
|
99683
|
+
}
|
|
99649
99684
|
}
|
|
99685
|
+
} catch {
|
|
99650
99686
|
}
|
|
99651
|
-
|
|
99652
|
-
|
|
99687
|
+
const hasAnyContent = prd || state || discussionsContent || transcriptsContent || notesContent || issueContext;
|
|
99688
|
+
if (!hasAnyContent) {
|
|
99689
|
+
return res.status(400).json({ error: "No planning artifacts, discussions, transcripts, or issue data to review against" });
|
|
99653
99690
|
}
|
|
99654
99691
|
let gitDiff = "";
|
|
99655
99692
|
let gitLog = "";
|
|
@@ -99681,12 +99718,29 @@ ${content.slice(0, 2e3)}
|
|
|
99681
99718
|
const centralReviewStatus = getReviewStatus(issueId.toUpperCase());
|
|
99682
99719
|
const reviewStatus = centralReviewStatus?.reviewStatus || "unknown";
|
|
99683
99720
|
const testStatus = centralReviewStatus?.testStatus || "unknown";
|
|
99721
|
+
const { createHash } = await import("crypto");
|
|
99722
|
+
const contentForHash = [prd, state, discussionsContent, transcriptsContent, notesContent, issueContext, gitDiff, gitLog, filesChanged, reviewStatus, testStatus].filter(Boolean).join("|");
|
|
99723
|
+
const contentHash = createHash("md5").update(contentForHash).digest("hex");
|
|
99724
|
+
const hashPath = join43(planningDir, ".status-review-hash");
|
|
99725
|
+
const statusReviewPath = join43(planningDir, "STATUS_REVIEW.md");
|
|
99726
|
+
if (existsSync44(hashPath) && existsSync44(statusReviewPath)) {
|
|
99727
|
+
const savedHash = readFileSync37(hashPath, "utf-8").trim();
|
|
99728
|
+
if (savedHash === contentHash) {
|
|
99729
|
+
const cachedReview = readFileSync37(statusReviewPath, "utf-8");
|
|
99730
|
+
const reviewedAt = statSync6(statusReviewPath).mtime.toISOString();
|
|
99731
|
+
console.log(`[status-review] ${issueId}: no changes detected, returning cached review`);
|
|
99732
|
+
return res.json({ success: true, statusReview: cachedReview, reviewedAt, cached: true });
|
|
99733
|
+
}
|
|
99734
|
+
}
|
|
99684
99735
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
99685
99736
|
let review;
|
|
99686
99737
|
try {
|
|
99687
99738
|
const analysisPrompt = `You are a technical project manager reviewing the implementation progress of a software feature.
|
|
99688
99739
|
|
|
99689
99740
|
## Issue: ${issueId}
|
|
99741
|
+
${issueContext ? `
|
|
99742
|
+
${issueContext}
|
|
99743
|
+
` : ""}
|
|
99690
99744
|
|
|
99691
99745
|
## Pipeline Status
|
|
99692
99746
|
- Review: ${reviewStatus}
|
|
@@ -99710,16 +99764,23 @@ ${gitLog || "No commits yet"}
|
|
|
99710
99764
|
## Discussions & Comments
|
|
99711
99765
|
${discussionsContent || "(No discussions synced)"}
|
|
99712
99766
|
|
|
99767
|
+
## Meeting Transcripts
|
|
99768
|
+
${transcriptsContent || "(No transcripts uploaded)"}
|
|
99769
|
+
|
|
99770
|
+
## Notes
|
|
99771
|
+
${notesContent || "(No notes uploaded)"}
|
|
99772
|
+
|
|
99713
99773
|
---
|
|
99714
99774
|
|
|
99715
|
-
Based on the above, produce a concise status review in markdown format with these sections:
|
|
99775
|
+
Based on ALL the above context, produce a concise status review in markdown format with these sections:
|
|
99716
99776
|
|
|
99717
99777
|
1. **Summary** (2-3 sentences: overall progress, what's done, what's remaining)
|
|
99718
|
-
2. **
|
|
99719
|
-
3. **Risk Assessment** (any concerns about code quality, missing tests, incomplete features)
|
|
99720
|
-
4. **
|
|
99778
|
+
2. **Requirements Coverage** (which requirements are met, partially met, or not yet started \u2014 use a table. If no PRD, summarize from discussions/transcripts/issue tracker data)
|
|
99779
|
+
3. **Risk Assessment** (any concerns about code quality, missing tests, incomplete features, blockers mentioned in discussions)
|
|
99780
|
+
4. **Key Decisions & Context** (important points from discussions, transcripts, or notes that affect the work)
|
|
99781
|
+
5. **Recommendation** (next steps, whether it's ready for review/merge, or what needs attention)
|
|
99721
99782
|
|
|
99722
|
-
Be specific and reference actual file names, requirements, and
|
|
99783
|
+
Be specific and reference actual file names, requirements, discussion points, and transcript highlights. Keep it under 600 words.`;
|
|
99723
99784
|
const aiReview = await callLLM(analysisPrompt);
|
|
99724
99785
|
review = `# Status Review - ${issueId}
|
|
99725
99786
|
|
|
@@ -99761,12 +99822,21 @@ ${gitLog || "No commits yet"}
|
|
|
99761
99822
|
## Discussions
|
|
99762
99823
|
${discussionsContent || "(No discussions synced)"}
|
|
99763
99824
|
|
|
99825
|
+
## Transcripts
|
|
99826
|
+
${transcriptsContent || "(No transcripts uploaded)"}
|
|
99827
|
+
|
|
99828
|
+
## Notes
|
|
99829
|
+
${notesContent || "(No notes uploaded)"}
|
|
99830
|
+
|
|
99831
|
+
${issueContext ? `## Issue Tracker Data
|
|
99832
|
+
${issueContext}
|
|
99833
|
+
` : ""}
|
|
99764
99834
|
---
|
|
99765
99835
|
*Review by Panopticon Mission Control (static fallback)*
|
|
99766
99836
|
`;
|
|
99767
99837
|
}
|
|
99768
|
-
const statusReviewPath = join43(planningDir, "STATUS_REVIEW.md");
|
|
99769
99838
|
writeFileSync30(statusReviewPath, review, "utf-8");
|
|
99839
|
+
writeFileSync30(hashPath, contentHash, "utf-8");
|
|
99770
99840
|
res.json({ success: true, statusReview: review, reviewedAt: now });
|
|
99771
99841
|
} catch (error) {
|
|
99772
99842
|
res.status(500).json({ error: "Failed to generate status review: " + error.message });
|