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-qJWm8JDC.js"></script>
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">
@@ -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
- if (!prd && !state) {
99640
- return res.status(400).json({ error: "No PRD or STATE.md to review against" });
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. **PRD Coverage** (which requirements are met, partially met, or not yet started \u2014 use a table)
99704
- 3. **Risk Assessment** (any concerns about code quality, missing tests, incomplete features)
99705
- 4. **Recommendation** (next steps, whether it's ready for review/merge, or what needs attention)
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 requirements. Keep it under 500 words.`;
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 });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "panopticon-cli",
3
- "version": "0.4.26",
3
+ "version": "0.4.28",
4
4
  "description": "Multi-agent orchestration for AI coding assistants (Claude Code, Codex, Cursor, Gemini CLI)",
5
5
  "keywords": [
6
6
  "ai-agents",