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-C8Vc3yIh.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,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 discussionsDir = join43(planningDir, "discussions");
99640
- let discussionsContent = "";
99641
- if (existsSync44(discussionsDir)) {
99642
- const discussionFiles = readdirSync17(discussionsDir).filter((f) => f.endsWith(".md") || f.endsWith(".txt"));
99643
- for (const file of discussionFiles.slice(0, 5)) {
99644
- const content = readFileSync37(join43(discussionsDir, file), "utf-8");
99645
- discussionsContent += `
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, 2e3)}
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
- if (!prd && !state && !discussionsContent) {
99652
- return res.status(400).json({ error: "No PRD, STATE.md, or discussions to review against" });
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. **PRD Coverage** (which requirements are met, partially met, or not yet started \u2014 use a table. If no PRD, summarize based on available context)
99719
- 3. **Risk Assessment** (any concerns about code quality, missing tests, incomplete features)
99720
- 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)
99721
99782
 
99722
- Be specific and reference actual file names, requirements, and discussion points. Keep it under 500 words.`;
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 });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "panopticon-cli",
3
- "version": "0.4.27",
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",