panopticon-cli 0.4.26 → 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,8 +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
|
-
|
|
99640
|
-
|
|
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 `
|
|
99647
|
+
### ${file}
|
|
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}]
|
|
99681
|
+
`;
|
|
99682
|
+
}
|
|
99683
|
+
}
|
|
99684
|
+
}
|
|
99685
|
+
} catch {
|
|
99686
|
+
}
|
|
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" });
|
|
99641
99690
|
}
|
|
99642
99691
|
let gitDiff = "";
|
|
99643
99692
|
let gitLog = "";
|
|
@@ -99669,12 +99718,29 @@ app.post("/api/mission-control/planning/:issueId/status-review", async (req, res
|
|
|
99669
99718
|
const centralReviewStatus = getReviewStatus(issueId.toUpperCase());
|
|
99670
99719
|
const reviewStatus = centralReviewStatus?.reviewStatus || "unknown";
|
|
99671
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
|
+
}
|
|
99672
99735
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
99673
99736
|
let review;
|
|
99674
99737
|
try {
|
|
99675
99738
|
const analysisPrompt = `You are a technical project manager reviewing the implementation progress of a software feature.
|
|
99676
99739
|
|
|
99677
99740
|
## Issue: ${issueId}
|
|
99741
|
+
${issueContext ? `
|
|
99742
|
+
${issueContext}
|
|
99743
|
+
` : ""}
|
|
99678
99744
|
|
|
99679
99745
|
## Pipeline Status
|
|
99680
99746
|
- Review: ${reviewStatus}
|
|
@@ -99695,16 +99761,26 @@ ${gitDiff || "No diff available"}
|
|
|
99695
99761
|
## Recent Commits
|
|
99696
99762
|
${gitLog || "No commits yet"}
|
|
99697
99763
|
|
|
99764
|
+
## Discussions & Comments
|
|
99765
|
+
${discussionsContent || "(No discussions synced)"}
|
|
99766
|
+
|
|
99767
|
+
## Meeting Transcripts
|
|
99768
|
+
${transcriptsContent || "(No transcripts uploaded)"}
|
|
99769
|
+
|
|
99770
|
+
## Notes
|
|
99771
|
+
${notesContent || "(No notes uploaded)"}
|
|
99772
|
+
|
|
99698
99773
|
---
|
|
99699
99774
|
|
|
99700
|
-
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:
|
|
99701
99776
|
|
|
99702
99777
|
1. **Summary** (2-3 sentences: overall progress, what's done, what's remaining)
|
|
99703
|
-
2. **
|
|
99704
|
-
3. **Risk Assessment** (any concerns about code quality, missing tests, incomplete features)
|
|
99705
|
-
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)
|
|
99706
99782
|
|
|
99707
|
-
Be specific and reference actual file names and
|
|
99783
|
+
Be specific and reference actual file names, requirements, discussion points, and transcript highlights. Keep it under 600 words.`;
|
|
99708
99784
|
const aiReview = await callLLM(analysisPrompt);
|
|
99709
99785
|
review = `# Status Review - ${issueId}
|
|
99710
99786
|
|
|
@@ -99743,12 +99819,24 @@ ${filesChanged || "No changes detected"}
|
|
|
99743
99819
|
${gitLog || "No commits yet"}
|
|
99744
99820
|
\`\`\`
|
|
99745
99821
|
|
|
99822
|
+
## Discussions
|
|
99823
|
+
${discussionsContent || "(No discussions synced)"}
|
|
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
|
+
` : ""}
|
|
99746
99834
|
---
|
|
99747
99835
|
*Review by Panopticon Mission Control (static fallback)*
|
|
99748
99836
|
`;
|
|
99749
99837
|
}
|
|
99750
|
-
const statusReviewPath = join43(planningDir, "STATUS_REVIEW.md");
|
|
99751
99838
|
writeFileSync30(statusReviewPath, review, "utf-8");
|
|
99839
|
+
writeFileSync30(hashPath, contentHash, "utf-8");
|
|
99752
99840
|
res.json({ success: true, statusReview: review, reviewedAt: now });
|
|
99753
99841
|
} catch (error) {
|
|
99754
99842
|
res.status(500).json({ error: "Failed to generate status review: " + error.message });
|