@rashidee/co2 1.3.25 → 1.3.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.
Files changed (70) hide show
  1. package/dist/.co2-dat/app.db +0 -0
  2. package/dist/.co2-dat/app.db-shm +0 -0
  3. package/dist/.co2-dat/app.db-wal +0 -0
  4. package/dist/index.js +179 -36
  5. package/package.json +2 -2
  6. package/plugin/.claude-plugin/plugin.json +22 -22
  7. package/plugin/skills/conductor-defect/SKILL.md +924 -905
  8. package/static/assets/{abnfDiagram-VRR7QNED-r3_rpvFo.js → abnfDiagram-VRR7QNED-DGTYgRnP.js} +1 -1
  9. package/static/assets/{arc-DbiqzTs-.js → arc-7174fU_E.js} +1 -1
  10. package/static/assets/{architectureDiagram-ZJ3FMSHR-BJ-dcYpi.js → architectureDiagram-ZJ3FMSHR-iMcDhvoF.js} +1 -1
  11. package/static/assets/{blockDiagram-677ZJIJ3-BmHNspIR.js → blockDiagram-677ZJIJ3-kM7BtLQy.js} +1 -1
  12. package/static/assets/{c4Diagram-LMCZKHZV-CfgVJ9gr.js → c4Diagram-LMCZKHZV-CIYw9y0n.js} +1 -1
  13. package/static/assets/channel-CZ6M3VBW.js +1 -0
  14. package/static/assets/{chunk-2Q5K7J3B-PNfiudSM.js → chunk-2Q5K7J3B-CwNDUll4.js} +1 -1
  15. package/static/assets/{chunk-32BRIVSS-DdD3xMjB.js → chunk-32BRIVSS-xUXN4448.js} +1 -1
  16. package/static/assets/{chunk-5VM5RSS4-DS1ulZwP.js → chunk-5VM5RSS4-DSuopQRa.js} +1 -1
  17. package/static/assets/{chunk-EX3LRPZG-CzVStkKt.js → chunk-EX3LRPZG-DaP1AUXn.js} +1 -1
  18. package/static/assets/{chunk-JWPE2WC7-De7uOmha.js → chunk-JWPE2WC7-BbcXokVM.js} +1 -1
  19. package/static/assets/{chunk-MOJQB5TN-qyl8h8E8.js → chunk-MOJQB5TN-BEvtZ0cJ.js} +1 -1
  20. package/static/assets/{chunk-RYQCIY6F-DQEjm1TG.js → chunk-RYQCIY6F-Cf9iaXLG.js} +1 -1
  21. package/static/assets/{chunk-V7JOEXUC-CHii2kCZ.js → chunk-V7JOEXUC-VoptRUQS.js} +1 -1
  22. package/static/assets/{chunk-VR4S4FIN-Y8HV5BKK.js → chunk-VR4S4FIN-D8MhSl2b.js} +1 -1
  23. package/static/assets/{chunk-XXDRQBXY-s_-4DXsy.js → chunk-XXDRQBXY-ChGrQH2-.js} +1 -1
  24. package/static/assets/classDiagram-OUVF2IWQ-BNo52yZj.js +1 -0
  25. package/static/assets/classDiagram-v2-EOCWNBFH-BNo52yZj.js +1 -0
  26. package/static/assets/{cose-bilkent-JH36ORCC-BeDdmDpD.js → cose-bilkent-JH36ORCC-_7_J1ueO.js} +1 -1
  27. package/static/assets/{cynefin-VYW2F7L2-COUQslLO.js → cynefin-VYW2F7L2-D7ojj48a.js} +1 -1
  28. package/static/assets/{cynefinDiagram-TSTJHNR4-BuPYyXEY.js → cynefinDiagram-TSTJHNR4-CzZCuws6.js} +1 -1
  29. package/static/assets/{dagre-VKFMJZFB-vqTchcyP.js → dagre-VKFMJZFB-DrShlPqK.js} +1 -1
  30. package/static/assets/{diagram-FQU43EPY-K_M0RuV-.js → diagram-FQU43EPY-Ba6vyx0R.js} +1 -1
  31. package/static/assets/{diagram-G47NLZAW-DZQ1eHWp.js → diagram-G47NLZAW-g1iqjkWC.js} +1 -1
  32. package/static/assets/{diagram-NH7WQ7WH-ayYySNnw.js → diagram-NH7WQ7WH-Yn0iGo61.js} +1 -1
  33. package/static/assets/{diagram-OA4YK3LP-D62rbwWX.js → diagram-OA4YK3LP-BqNMfzEH.js} +1 -1
  34. package/static/assets/{diagram-WEI45ONY-BgBuxQAR.js → diagram-WEI45ONY-Jv0HskWN.js} +1 -1
  35. package/static/assets/{ebnfDiagram-CCIWWBDH-koE_7EDL.js → ebnfDiagram-CCIWWBDH-EVPmY5ND.js} +1 -1
  36. package/static/assets/{erDiagram-Q63AITRT-AjFwiuV7.js → erDiagram-Q63AITRT-BrFEQzOf.js} +1 -1
  37. package/static/assets/{flowDiagram-23GEKE2U-C0R1nVvy.js → flowDiagram-23GEKE2U-CKQmfCK8.js} +1 -1
  38. package/static/assets/{ganttDiagram-NO4QXBWP-CY-FcEEG.js → ganttDiagram-NO4QXBWP-DOQ3sYfu.js} +1 -1
  39. package/static/assets/{gitGraphDiagram-IHSO6WYX-DyJl7oIu.js → gitGraphDiagram-IHSO6WYX-DamxyOBX.js} +1 -1
  40. package/static/assets/{index-DFOlKDT-.css → index-BRho3Z-u.css} +1 -1
  41. package/static/assets/index-DKK3AwQd.js +496 -0
  42. package/static/assets/{infoDiagram-FWYZ7A6U-DHmQrTFz.js → infoDiagram-FWYZ7A6U-BvfLUhKQ.js} +1 -1
  43. package/static/assets/{ishikawaDiagram-FXEZZL3T-Rrb_rX1Z.js → ishikawaDiagram-FXEZZL3T-Bjcn3YwT.js} +1 -1
  44. package/static/assets/{journeyDiagram-5HDEW3XC-C1X2-E8O.js → journeyDiagram-5HDEW3XC-C7zgXG_P.js} +1 -1
  45. package/static/assets/{kanban-definition-HUTT4EX6-6taKamuj.js → kanban-definition-HUTT4EX6-DkQNMRHb.js} +1 -1
  46. package/static/assets/{linear-BgfvUII2.js → linear-DUJurxs_.js} +1 -1
  47. package/static/assets/{mindmap-definition-LN4V7U3C-CMIdnZlB.js → mindmap-definition-LN4V7U3C-Ca8Rx7ow.js} +1 -1
  48. package/static/assets/{pegDiagram-2B236MQR-Ds5tsqTv.js → pegDiagram-2B236MQR-DM2f6zFq.js} +1 -1
  49. package/static/assets/{pieDiagram-ENE6RG2P-2nFB-KUn.js → pieDiagram-ENE6RG2P-DZQJ9aJe.js} +1 -1
  50. package/static/assets/{quadrantDiagram-ABIIQ3AL-CXYP7EpA.js → quadrantDiagram-ABIIQ3AL-dN5N3iXz.js} +1 -1
  51. package/static/assets/{railroadDiagram-RFXS5EU6-ZWvggJi6.js → railroadDiagram-RFXS5EU6-CxVvDIJC.js} +1 -1
  52. package/static/assets/{requirementDiagram-TGXJPOKE-B9pmz1Lq.js → requirementDiagram-TGXJPOKE-D8gSZdJO.js} +1 -1
  53. package/static/assets/{sankeyDiagram-HTMAVEWB-p05V4NVU.js → sankeyDiagram-HTMAVEWB-CKqKdt9n.js} +1 -1
  54. package/static/assets/{sequenceDiagram-DBY2YBRQ-L1U6b6XO.js → sequenceDiagram-DBY2YBRQ-BUTyVZbB.js} +1 -1
  55. package/static/assets/{sizeCapture-X5ZJPWSS-DaxMca0_.js → sizeCapture-X5ZJPWSS-BfeUsrrc.js} +1 -1
  56. package/static/assets/{stateDiagram-2N3HPSRC-Cn9Oa3AO.js → stateDiagram-2N3HPSRC-CccstMMZ.js} +1 -1
  57. package/static/assets/stateDiagram-v2-6OUMAXLB-BYik3bHQ.js +1 -0
  58. package/static/assets/{swimlanes-5IMT3BWC-CB2axDli.js → swimlanes-5IMT3BWC-WuBhb5Nm.js} +2 -2
  59. package/static/assets/swimlanesDiagram-G3AALYLV-pwhS7TR2.js +8 -0
  60. package/static/assets/{timeline-definition-FHXFAJF6-CBjRTzLu.js → timeline-definition-FHXFAJF6-DE4hFXfn.js} +1 -1
  61. package/static/assets/{vennDiagram-L72KCM5P-CU3sHFkZ.js → vennDiagram-L72KCM5P-lV9K4hR0.js} +1 -1
  62. package/static/assets/{wardleyDiagram-EHGQE667-BUEYUFnX.js → wardleyDiagram-EHGQE667-Dbkoleze.js} +1 -1
  63. package/static/assets/{xychartDiagram-FW5EYKEG-CsQatKqg.js → xychartDiagram-FW5EYKEG-BHYUnMjh.js} +1 -1
  64. package/static/index.html +2 -2
  65. package/static/assets/channel-oJjZid9v.js +0 -1
  66. package/static/assets/classDiagram-OUVF2IWQ-BBGkNxZZ.js +0 -1
  67. package/static/assets/classDiagram-v2-EOCWNBFH-BBGkNxZZ.js +0 -1
  68. package/static/assets/index-B6KU4H2y.js +0 -496
  69. package/static/assets/stateDiagram-v2-6OUMAXLB-Cd04vp8B.js +0 -1
  70. package/static/assets/swimlanesDiagram-G3AALYLV-GtoFqFbp.js +0 -8
Binary file
Binary file
Binary file
package/dist/index.js CHANGED
@@ -6809,8 +6809,8 @@ var {
6809
6809
  // package.json
6810
6810
  var package_default = {
6811
6811
  name: "@rashidee/co2",
6812
- version: "1.3.25",
6813
- description: "Compound Context Studio \u2014 self-hosted team context authoring for CO2 projects",
6812
+ version: "1.3.28",
6813
+ description: "Compound Context Studio \xC3\u0192\xC2\xA2\xC3\xA2\xE2\u20AC\u0161\xC2\xAC\xC3\xA2\xE2\u201A\xAC\xC2\x9D self-hosted team context authoring for CO2 projects",
6814
6814
  type: "module",
6815
6815
  license: "MIT",
6816
6816
  publishConfig: {
@@ -12320,8 +12320,10 @@ var bugReports = sqliteTable("bug_reports", {
12320
12320
  title: text("title").notNull(),
12321
12321
  description: text("description"),
12322
12322
  // [v1.5.1] severity dropped — the CO2 BUG.md standard carries no severity level.
12323
+ // 'rejected' — withdrawn report, superseded by a new one (type-level only; the column has
12324
+ // no CHECK constraint, so no migration is needed).
12323
12325
  status: text("status", {
12324
- enum: ["open", "in_fix", "fixed", "verified", "closed"]
12326
+ enum: ["open", "in_fix", "fixed", "verified", "closed", "rejected"]
12325
12327
  }).notNull().default("open"),
12326
12328
  // [v1.8.0] CO2 BUG.md is grouped by module — the module name verbatim from the CLAUDE.md
12327
12329
  // registry / imported BUG.md section (migration 0014 ALTER ADD). NULL → `# Common Module`.
@@ -19567,7 +19569,7 @@ var dashboardProjectSchema = external_exports.object({
19567
19569
  });
19568
19570
 
19569
19571
  // ../core/src/schemas/defect.ts
19570
- var bugStatusSchema = external_exports.enum(["open", "in_fix", "fixed", "verified", "closed"]);
19572
+ var bugStatusSchema = external_exports.enum(["open", "in_fix", "fixed", "verified", "closed", "rejected"]);
19571
19573
  var EDITABLE_BUG_STATUSES = ["open", "in_fix"];
19572
19574
  var REOPENABLE_BUG_STATUSES = ["open", "in_fix", "fixed"];
19573
19575
  var reopenBugsSchema = external_exports.object({
@@ -19589,6 +19591,10 @@ var createBugReportSchema = external_exports.object({
19589
19591
  var updateBugStatusSchema = external_exports.object({
19590
19592
  status: bugStatusSchema
19591
19593
  });
19594
+ var moveBugReportSchema = external_exports.object({
19595
+ applicationId: external_exports.number().int().positive(),
19596
+ module: external_exports.string().max(120).optional()
19597
+ });
19592
19598
  var updateBugReportSchema = external_exports.object({
19593
19599
  title: external_exports.string().min(1).max(200),
19594
19600
  description: external_exports.string().optional(),
@@ -24575,10 +24581,55 @@ function updateBugReport(db, workspacePath, bugId, input) {
24575
24581
  syncBugMdToDisk(db, workspacePath, existing.applicationId, bugId);
24576
24582
  }
24577
24583
  function updateBugStatus(db, workspacePath, bugId, status) {
24578
- const existing = db.select({ id: bugReports.id, applicationId: bugReports.applicationId }).from(bugReports).where(and(eq(bugReports.id, bugId), eq(bugReports.isDeleted, 0))).get();
24584
+ const existing = db.select({
24585
+ id: bugReports.id,
24586
+ title: bugReports.title,
24587
+ applicationId: bugReports.applicationId
24588
+ }).from(bugReports).where(and(eq(bugReports.id, bugId), eq(bugReports.isDeleted, 0))).get();
24579
24589
  if (!existing) throw svcError11("BUG_NOT_FOUND", 404);
24580
24590
  db.update(bugReports).set({ status, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(eq(bugReports.id, bugId)).run();
24581
- syncBugMdToDisk(db, workspacePath, existing.applicationId, bugId);
24591
+ if (status === "rejected") {
24592
+ removeBugBulletFromDisk(db, workspacePath, existing.applicationId, existing);
24593
+ } else {
24594
+ syncBugMdToDisk(db, workspacePath, existing.applicationId, bugId);
24595
+ }
24596
+ }
24597
+ function moveBugReport(db, workspacePath, bugId, input) {
24598
+ const existing = db.select().from(bugReports).where(and(eq(bugReports.id, bugId), eq(bugReports.isDeleted, 0))).get();
24599
+ if (!existing) throw svcError11("BUG_NOT_FOUND", 404);
24600
+ if (!EDITABLE_BUG_STATUSES.includes(existing.status)) throw svcError11("BUG_NOT_MOVABLE", 409);
24601
+ const target = db.select({ id: applications.id, projectId: applications.projectId }).from(applications).where(eq(applications.id, input.applicationId)).get();
24602
+ if (!target || target.projectId !== existing.projectId) {
24603
+ throw svcError11("APPLICATION_NOT_FOUND", 404);
24604
+ }
24605
+ const targetModule = input.module?.trim() || null;
24606
+ const sameModule = (existing.module?.toLowerCase() ?? null) === (targetModule?.toLowerCase() ?? null);
24607
+ if (existing.applicationId === input.applicationId && sameModule) {
24608
+ throw svcError11("MOVE_NO_CHANGE", 400);
24609
+ }
24610
+ db.update(bugReports).set({
24611
+ applicationId: input.applicationId,
24612
+ module: targetModule,
24613
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
24614
+ }).where(eq(bugReports.id, bugId)).run();
24615
+ removeBugBulletFromDisk(db, workspacePath, existing.applicationId, existing);
24616
+ syncBugMdToDisk(db, workspacePath, input.applicationId, bugId, "insert");
24617
+ return getBugReport(db, bugId);
24618
+ }
24619
+ function removeBugBulletFromDisk(db, workspacePath, applicationId, bug) {
24620
+ try {
24621
+ const app = db.select({ id: applications.id, name: applications.name, projectId: applications.projectId }).from(applications).where(eq(applications.id, applicationId)).get();
24622
+ if (!app) return;
24623
+ const project = db.select({ workspaceFolderName: projects.workspaceFolderName }).from(projects).where(eq(projects.id, app.projectId)).get();
24624
+ if (!project) return;
24625
+ const projectDir2 = join21(workspacePath, project.workspaceFolderName);
24626
+ const file = join21(projectDir2, resolveAppFolderName(projectDir2, app.name), "context", "BUG.md");
24627
+ if (!existsSync19(file)) return;
24628
+ const removed = removeBugFromBugMd(readFileSync13(file, "utf8"), bugCodeAndTitle(bug).code);
24629
+ if (removed !== null) writeFileSync11(file, removed, "utf8");
24630
+ else writeBugMdFile(db, workspacePath, app, project.workspaceFolderName);
24631
+ } catch {
24632
+ }
24582
24633
  }
24583
24634
  function reopenBugReports(db, workspacePath, bugIds, userId) {
24584
24635
  if (bugIds.length === 0) throw svcError11("NO_BUGS_SELECTED", 400);
@@ -24677,6 +24728,37 @@ var MD_HR = /^-{3,}\s*$/;
24677
24728
  var MD_BULLET = /^-\s+(?:~~)?\s*\[BUG-\d+\]/;
24678
24729
  var MD_LEGACY_HEADING = /^##\s+(?:~~)?\s*\[BUG-\d+\]/;
24679
24730
  var isStructural = (line) => MD_HEADING.test(line) || MD_VERSION.test(line) || MD_HR.test(line) || MD_BULLET.test(line);
24731
+ function bulletExtent(lines, code) {
24732
+ const codeRe = new RegExp(`^-\\s+(?:~~)?\\s*\\[${code}\\]`);
24733
+ const start = lines.findIndex((l) => codeRe.test(l));
24734
+ if (start === -1) return null;
24735
+ let end = start + 1;
24736
+ while (end < lines.length) {
24737
+ const line = lines[end];
24738
+ if (line.trim() === "") {
24739
+ let peek = end + 1;
24740
+ while (peek < lines.length && lines[peek].trim() === "") peek++;
24741
+ if (peek < lines.length && !isStructural(lines[peek])) {
24742
+ end = peek + 1;
24743
+ continue;
24744
+ }
24745
+ break;
24746
+ }
24747
+ if (isStructural(line)) break;
24748
+ end++;
24749
+ }
24750
+ return { start, end };
24751
+ }
24752
+ function removeBugFromBugMd(content, code) {
24753
+ const bom = content.startsWith("\uFEFF") ? "\uFEFF" : "";
24754
+ const eol = content.includes("\r\n") ? "\r\n" : "\n";
24755
+ const lines = (bom ? content.slice(1) : content).split(/\r?\n/);
24756
+ if (lines.some((l) => MD_LEGACY_HEADING.test(l))) return null;
24757
+ const extent = bulletExtent(lines, code);
24758
+ if (!extent) return content;
24759
+ lines.splice(extent.start, extent.end - extent.start);
24760
+ return bom + lines.join(eol);
24761
+ }
24680
24762
  function mergeBugIntoBugMd(content, bug, semver, moduleCategory, mode) {
24681
24763
  const bom = content.startsWith("\uFEFF") ? "\uFEFF" : "";
24682
24764
  const eol = content.includes("\r\n") ? "\r\n" : "\n";
@@ -24685,25 +24767,9 @@ function mergeBugIntoBugMd(content, bug, semver, moduleCategory, mode) {
24685
24767
  const bullet = bugBulletLines(bug);
24686
24768
  const { code } = bugCodeAndTitle(bug);
24687
24769
  if (mode === "replace") {
24688
- const codeRe = new RegExp(`^-\\s+(?:~~)?\\s*\\[${code}\\]`);
24689
- const start = lines.findIndex((l) => codeRe.test(l));
24690
- if (start !== -1) {
24691
- let end = start + 1;
24692
- while (end < lines.length) {
24693
- const line = lines[end];
24694
- if (line.trim() === "") {
24695
- let peek = end + 1;
24696
- while (peek < lines.length && lines[peek].trim() === "") peek++;
24697
- if (peek < lines.length && !isStructural(lines[peek])) {
24698
- end = peek + 1;
24699
- continue;
24700
- }
24701
- break;
24702
- }
24703
- if (isStructural(line)) break;
24704
- end++;
24705
- }
24706
- lines.splice(start, end - start, ...bullet);
24770
+ const extent = bulletExtent(lines, code);
24771
+ if (extent) {
24772
+ lines.splice(extent.start, extent.end - extent.start, ...bullet);
24707
24773
  return bom + lines.join(eol);
24708
24774
  }
24709
24775
  }
@@ -24782,7 +24848,13 @@ function mergeBugIntoBugMd(content, bug, semver, moduleCategory, mode) {
24782
24848
  return bom + lines.join(eol);
24783
24849
  }
24784
24850
  function writeBugMdFile(db, workspacePath, app, projectFolderName) {
24785
- const bugs = db.select().from(bugReports).where(and(eq(bugReports.applicationId, app.id), eq(bugReports.isDeleted, 0))).all();
24851
+ const bugs = db.select().from(bugReports).where(
24852
+ and(
24853
+ eq(bugReports.applicationId, app.id),
24854
+ eq(bugReports.isDeleted, 0),
24855
+ ne(bugReports.status, "rejected")
24856
+ )
24857
+ ).all();
24786
24858
  const modules = db.select({ name: projectModules.name, category: projectModules.category }).from(projectModules).where(and(eq(projectModules.applicationId, app.id), eq(projectModules.isDeleted, 0))).orderBy(projectModules.displayOrder, projectModules.id).all();
24787
24859
  const semverByVersionId = new Map(
24788
24860
  db.select({ id: prdVersions.id, semver: prdVersions.semver }).from(prdVersions).where(eq(prdVersions.projectId, app.projectId)).all().map((v) => [v.id, v.semver])
@@ -24808,7 +24880,8 @@ function syncBugStatusesFromMaster(db, trackingFilePath, applicationId) {
24808
24880
  let updated = 0;
24809
24881
  const now = (/* @__PURE__ */ new Date()).toISOString();
24810
24882
  for (const row of rows) {
24811
- if (row.status === "verified" || row.status === "closed") continue;
24883
+ if (row.status === "verified" || row.status === "closed" || row.status === "rejected")
24884
+ continue;
24812
24885
  const entry = entries.get(bugCodeAndTitle(row).code);
24813
24886
  if (!entry) continue;
24814
24887
  const next = mapBugStatus(entry.status);
@@ -24934,6 +25007,19 @@ function defectRoutes(db, workspacePath) {
24934
25007
  return errorResponse5(c, e);
24935
25008
  }
24936
25009
  });
25010
+ const validateMove = zValidator("json", moveBugReportSchema, (result, c) => {
25011
+ if (!result.success) {
25012
+ return c.json({ code: "VALIDATION_FAILED", issues: result.error.issues }, 422);
25013
+ }
25014
+ });
25015
+ app.post("/:id{[0-9]+}/move", validateMove, (c) => {
25016
+ const id = Number(c.req.param("id"));
25017
+ try {
25018
+ return c.json({ moved: moveBugReport(db, workspacePath, id, c.req.valid("json")) });
25019
+ } catch (e) {
25020
+ return errorResponse5(c, e);
25021
+ }
25022
+ });
24937
25023
  const validateReopen = zValidator("json", reopenBugsSchema, (result, c) => {
24938
25024
  if (!result.success) {
24939
25025
  return c.json({ code: "VALIDATION_FAILED", issues: result.error.issues }, 422);
@@ -26614,6 +26700,32 @@ function rescanProjectWorkflows(db, workspacePath, projectId, user, watcherInter
26614
26700
  const currentVersionId = ensureBaselineVersion(db, projectId, user.id);
26615
26701
  const semver = db.select({ semver: prdVersions.semver }).from(prdVersions).where(eq(prdVersions.id, currentVersionId)).get()?.semver ?? null;
26616
26702
  const affectedForCurrentVersion = getVersionAffectedAppIds(db, projectId, currentVersionId);
26703
+ const bugAppsForCurrentVersion = getAppsWithBugsInVersion(db, projectId, currentVersionId);
26704
+ let prunedRuns = 0;
26705
+ const bugAppsByVersion = /* @__PURE__ */ new Map([
26706
+ [currentVersionId, bugAppsForCurrentVersion]
26707
+ ]);
26708
+ const discoveredQualityRows = db.select({ run: conductorRuns, wfmId: workflowMarkdowns.id, filePath: workflowMarkdowns.filePath }).from(conductorRuns).innerJoin(workflowMarkdowns, eq(workflowMarkdowns.id, conductorRuns.workflowMarkdownId)).where(
26709
+ and(
26710
+ eq(conductorRuns.projectId, projectId),
26711
+ inArray(conductorRuns.conductorType, ["quality", "defect"])
26712
+ )
26713
+ ).all();
26714
+ for (const { run, wfmId, filePath } of discoveredQualityRows) {
26715
+ if (!filePath.endsWith("BUG_MASTER.md")) continue;
26716
+ const versionId = run.prdVersionId ?? currentVersionId;
26717
+ let bugApps = bugAppsByVersion.get(versionId);
26718
+ if (!bugApps) {
26719
+ bugApps = getAppsWithBugsInVersion(db, projectId, versionId);
26720
+ bugAppsByVersion.set(versionId, bugApps);
26721
+ }
26722
+ if (bugApps.has(run.applicationId)) continue;
26723
+ stopWatcher(run.id);
26724
+ db.delete(conductorRuns).where(eq(conductorRuns.id, run.id)).run();
26725
+ const remaining = db.select({ id: conductorRuns.id }).from(conductorRuns).where(eq(conductorRuns.workflowMarkdownId, wfmId)).limit(1).get();
26726
+ if (!remaining) db.delete(workflowMarkdowns).where(eq(workflowMarkdowns.id, wfmId)).run();
26727
+ prunedRuns++;
26728
+ }
26617
26729
  let discoveredRuns = 0;
26618
26730
  const now = (/* @__PURE__ */ new Date()).toISOString();
26619
26731
  for (const app of apps) {
@@ -26624,6 +26736,9 @@ function rescanProjectWorkflows(db, workspacePath, projectId, user, watcherInter
26624
26736
  if ((conductorType === "prepare" || conductorType === "develop") && affectedForCurrentVersion !== null && !affectedForCurrentVersion.has(app.id)) {
26625
26737
  continue;
26626
26738
  }
26739
+ if (conductorType === "quality" && !bugAppsForCurrentVersion.has(app.id)) {
26740
+ continue;
26741
+ }
26627
26742
  const aliases = conductorType === "quality" ? ["quality", "defect"] : [conductorType];
26628
26743
  const known = db.select({
26629
26744
  status: conductorRuns.status,
@@ -26717,7 +26832,7 @@ function rescanProjectWorkflows(db, workspacePath, projectId, user, watcherInter
26717
26832
  }
26718
26833
  }
26719
26834
  }
26720
- return { rescannedRuns, discoveredRuns };
26835
+ return { rescannedRuns, discoveredRuns, prunedRuns };
26721
26836
  }
26722
26837
  function getWorkflowRun(db, workflowMarkdownId, workspacePath) {
26723
26838
  const wfm = db.select().from(workflowMarkdowns).where(eq(workflowMarkdowns.id, workflowMarkdownId)).get();
@@ -26743,14 +26858,7 @@ function getRunApplicationChangelog(db, workspacePath, workflowMarkdownId, appNa
26743
26858
  if (!wfm) throw svcError14("RUN_NOT_FOUND", 404);
26744
26859
  const project = db.select().from(projects).where(eq(projects.id, wfm.projectId)).get();
26745
26860
  if (!project) throw svcError14("PROJECT_NOT_FOUND", 404);
26746
- let runAppNames;
26747
- if (wfm.importedAppName) {
26748
- runAppNames = [wfm.importedAppName];
26749
- } else {
26750
- const appIds = db.select({ applicationId: conductorRuns.applicationId }).from(conductorRuns).where(eq(conductorRuns.workflowMarkdownId, wfm.id)).all().map((r) => r.applicationId);
26751
- runAppNames = appIds.length > 0 ? db.select({ name: applications.name }).from(applications).where(inArray(applications.id, appIds)).all().map((a) => a.name) : [];
26752
- }
26753
- if (!runAppNames.includes(appName)) throw svcError14("APP_NOT_IN_RUN", 404);
26861
+ if (!runApplicationNames(db, wfm).includes(appName)) throw svcError14("APP_NOT_IN_RUN", 404);
26754
26862
  const projectDir2 = resolve2(workspacePath, project.workspaceFolderName);
26755
26863
  const appFolder = resolveAppFolderName(projectDir2, appName);
26756
26864
  const absolute = resolve2(projectDir2, appFolder, "CHANGELOG.md");
@@ -26763,6 +26871,30 @@ function getRunApplicationChangelog(db, workspacePath, workflowMarkdownId, appNa
26763
26871
  content: readFileSync17(absolute, "utf-8")
26764
26872
  };
26765
26873
  }
26874
+ function runApplicationNames(db, wfm) {
26875
+ if (wfm.importedAppName) return [wfm.importedAppName];
26876
+ const appIds = db.select({ applicationId: conductorRuns.applicationId }).from(conductorRuns).where(eq(conductorRuns.workflowMarkdownId, wfm.id)).all().map((r) => r.applicationId);
26877
+ if (appIds.length === 0) return [];
26878
+ return db.select({ name: applications.name }).from(applications).where(inArray(applications.id, appIds)).all().map((a) => a.name);
26879
+ }
26880
+ function getRunApplicationTracker(db, workspacePath, workflowMarkdownId, appName) {
26881
+ const wfm = db.select().from(workflowMarkdowns).where(eq(workflowMarkdowns.id, workflowMarkdownId)).get();
26882
+ if (!wfm) throw svcError14("RUN_NOT_FOUND", 404);
26883
+ if (wfm.conductorType === "prepare") throw svcError14("NO_TRACKER_FOR_CONDUCTOR", 400);
26884
+ const project = db.select().from(projects).where(eq(projects.id, wfm.projectId)).get();
26885
+ if (!project) throw svcError14("PROJECT_NOT_FOUND", 404);
26886
+ if (!runApplicationNames(db, wfm).includes(appName)) throw svcError14("APP_NOT_IN_RUN", 404);
26887
+ const projectDir2 = resolve2(workspacePath, project.workspaceFolderName);
26888
+ const absolute = resolve2(resolveRunTrackingFilePath(projectDir2, appName, wfm.conductorType));
26889
+ if (absolute !== projectDir2 && !absolute.startsWith(projectDir2 + sep2))
26890
+ throw svcError14("INVALID_PATH", 400);
26891
+ if (!existsSync23(absolute)) throw svcError14("TRACKER_NOT_FOUND", 404);
26892
+ return {
26893
+ applicationName: appName,
26894
+ filePath: relative(workspacePath, absolute).replace(/\\/g, "/"),
26895
+ content: readFileSync17(absolute, "utf-8")
26896
+ };
26897
+ }
26766
26898
  function toDetail(db, projectFolder, wfm, workspacePath) {
26767
26899
  if (wfm.importedAppName) {
26768
26900
  return {
@@ -28005,6 +28137,17 @@ function workflowRoutes(db, workspacePath) {
28005
28137
  return errorResponse16(c, e);
28006
28138
  }
28007
28139
  });
28140
+ app.get("/runs/:id/tracker", (c) => {
28141
+ const id = Number(c.req.param("id"));
28142
+ if (Number.isNaN(id)) return c.json({ code: "INVALID_ID" }, 400);
28143
+ const appName = c.req.query("app");
28144
+ if (!appName) return c.json({ code: "APP_REQUIRED" }, 400);
28145
+ try {
28146
+ return c.json(getRunApplicationTracker(db, workspacePath, id, appName));
28147
+ } catch (e) {
28148
+ return errorResponse16(c, e);
28149
+ }
28150
+ });
28008
28151
  app.post("/runs/:id/force-stop", (c) => {
28009
28152
  const id = Number(c.req.param("id"));
28010
28153
  if (Number.isNaN(id)) return c.json({ code: "INVALID_ID" }, 400);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rashidee/co2",
3
- "version": "1.3.25",
4
- "description": "Compound Context Studio self-hosted team context authoring for CO2 projects",
3
+ "version": "1.3.28",
4
+ "description": "Compound Context Studio — self-hosted team context authoring for CO2 projects",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "publishConfig": {
@@ -1,22 +1,22 @@
1
- {
2
- "name": "co2-skills",
3
- "version": "1.8.4",
4
- "description": "Compound Context Skills an opinionated context engineering methodology for AI-driven software development. Generates data models, HTML mockups, technical specifications, test specifications, and orchestrates full-stack development from Agile user stories.",
5
- "author": {
6
- "name": "Rashidee M.Rashid"
7
- },
8
- "repository": "https://github.com/rashidee/co2-skills",
9
- "license": "MIT",
10
- "keywords": [
11
- "context-engineering",
12
- "user-stories",
13
- "code-generation",
14
- "ddd",
15
- "spring-boot",
16
- "laravel",
17
- "playwright",
18
- "mockups",
19
- "specifications",
20
- "data-modeling"
21
- ]
22
- }
1
+ {
2
+ "name": "co2-skills",
3
+ "version": "1.8.5",
4
+ "description": "Compound Context Skills — an opinionated context engineering methodology for AI-driven software development. Generates data models, HTML mockups, technical specifications, test specifications, and orchestrates full-stack development from Agile user stories.",
5
+ "author": {
6
+ "name": "Rashidee M.Rashid"
7
+ },
8
+ "repository": "https://github.com/rashidee/co2-skills",
9
+ "license": "MIT",
10
+ "keywords": [
11
+ "context-engineering",
12
+ "user-stories",
13
+ "code-generation",
14
+ "ddd",
15
+ "spring-boot",
16
+ "laravel",
17
+ "playwright",
18
+ "mockups",
19
+ "specifications",
20
+ "data-modeling"
21
+ ]
22
+ }