p-backlog 0.2.0

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 (36) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/LICENSE +201 -0
  3. package/README.md +218 -0
  4. package/README.ru.md +213 -0
  5. package/dist/cli.js +6712 -0
  6. package/dist/server.js +3887 -0
  7. package/dist/web/assets/ChartTooltip-BYCfK3J2.js +55 -0
  8. package/dist/web/assets/ChartTooltip-tQC8-pw2.css +1 -0
  9. package/dist/web/assets/CodeTab-CfG0h41u.css +1 -0
  10. package/dist/web/assets/CodeTab-LYNoYtUt.js +1 -0
  11. package/dist/web/assets/CostTab-BNukfYQ_.js +1 -0
  12. package/dist/web/assets/CostTab-CtmH2WbT.css +1 -0
  13. package/dist/web/assets/EffectTab-Bk8BtfaR.js +1 -0
  14. package/dist/web/assets/EffectTab-DCTwmWXb.css +1 -0
  15. package/dist/web/assets/Figure-BcMtR7CN.js +1 -0
  16. package/dist/web/assets/OverviewTab-Bv0rKc6p.js +1 -0
  17. package/dist/web/assets/OverviewTab-C-NPX9JB.css +1 -0
  18. package/dist/web/assets/QualityTab-N81paNFO.js +1 -0
  19. package/dist/web/assets/StatsPage-D4P63bqv.js +1 -0
  20. package/dist/web/assets/StatsPage-gITQDSrz.css +1 -0
  21. package/dist/web/assets/StatsPage.module-D8dvB8Va.js +1 -0
  22. package/dist/web/assets/StatsTabState-B6PD1sC0.css +1 -0
  23. package/dist/web/assets/StatsTabState-BcFrx-N3.js +1 -0
  24. package/dist/web/assets/StatsTable-C8h-1NJ7.js +1 -0
  25. package/dist/web/assets/StatsTable-Z9x-Xaha.css +1 -0
  26. package/dist/web/assets/UnavailableRepos-COXy5-Dn.js +1 -0
  27. package/dist/web/assets/i18n-BO0kwLac.js +58 -0
  28. package/dist/web/assets/i18n-BlPq0Oql.css +1 -0
  29. package/dist/web/assets/index-C-8JzRpY.js +38 -0
  30. package/dist/web/assets/index-DyGLN1aL.css +1 -0
  31. package/dist/web/assets/rolldown-runtime-hePW80VL.js +1 -0
  32. package/dist/web/assets/value-dot-X354sZLx.js +1 -0
  33. package/dist/web/index.html +16 -0
  34. package/package.json +90 -0
  35. package/skill/backlog/SKILL.md +182 -0
  36. package/skill/backlog-en/SKILL.md +194 -0
@@ -0,0 +1 @@
1
+ ._wrap_t6xj6_1{align-items:flex-start;gap:var(--space-1);flex-direction:column;margin-top:auto;display:flex}._switch_t6xj6_9{border:1px solid var(--line);border-radius:var(--radius-chip);background:var(--surface-sunken);gap:2px;padding:2px;display:inline-flex}._switch_t6xj6_9:has(button:disabled){opacity:.6}._button_t6xj6_22{padding:3px var(--space-2);border-radius:var(--radius-chip);color:var(--ink-muted);font-size:var(--text-sm);cursor:pointer;transition:background var(--duration) var(--ease-out), color var(--duration) var(--ease-out);background:0 0;border:0;font-weight:600}._button_t6xj6_22:hover{color:var(--ink)}._button_t6xj6_22:focus-visible{outline:2px solid var(--accent);outline-offset:2px}._button_t6xj6_22:disabled{cursor:not-allowed}._pressed_t6xj6_47{background:var(--surface-selected);color:var(--ink)}._error_t6xj6_52{text-wrap:pretty;max-width:220px;color:var(--danger-ink);font-size:var(--text-sm)}._dialog_luij2_1{width:min(420px, calc(100vw - 2 * var(--space-4)));padding:var(--space-4);border:1px solid var(--line);border-radius:var(--radius-panel);background:var(--surface-raised);color:var(--ink);box-shadow:var(--shadow-panel)}._dialog_luij2_1::backdrop{background:var(--scrim)}._title_luij2_15{margin:0 0 var(--space-2);font-size:var(--text-lg);font-weight:600}._description_luij2_21{margin:0 0 var(--space-3);color:var(--ink-muted)}._field_luij2_26{gap:var(--space-1);color:var(--ink-subtle);font-size:var(--text-sm);flex-direction:column;display:flex}._actions_luij2_34{justify-content:flex-end;gap:var(--space-2);margin-top:var(--space-4);display:flex}._checkbox_9cq3e_1{cursor:pointer;flex:none;justify-content:center;align-items:center;width:24px;height:24px;display:inline-flex}._checkbox_9cq3e_1 input{width:14px;height:14px;margin:0}._delete_9cq3e_17{border-radius:var(--radius-control);width:24px;height:24px;color:var(--ink-subtle);cursor:pointer;background:0 0;border:0;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}._delete_9cq3e_17:hover{background:var(--surface-hover);color:var(--danger-ink)}._error_9cq3e_37{contain:inline-size;text-wrap:pretty;color:var(--danger-ink);font-size:var(--text-sm);flex-basis:100%;order:1;margin-inline-end:calc(var(--row-gap,0px) * -1);padding-inline-start:var(--project-error-indent,calc(24px + var(--row-gap,0px)))}._skipLink_1rs5g_1:focus{top:var(--space-2);left:var(--space-2);z-index:var(--z-dialog);width:auto;height:auto;padding:var(--space-2) var(--space-3);clip-path:none;white-space:normal;border-radius:var(--radius-control);background:var(--surface-raised);color:var(--ink);margin:0;position:fixed;overflow:visible}._shell_1rs5g_18{background:var(--surface);grid-template-rows:minmax(0,1fr);grid-template-columns:260px minmax(0,1fr);height:100%;display:grid}._sidebar_1rs5g_26{gap:var(--space-4);padding:var(--space-4) var(--space-3);border-right:1px solid var(--line);background:var(--surface-sunken);flex-direction:column;display:flex;overflow-y:auto}._brand_1rs5g_36{padding:0 var(--space-2);font-size:var(--text-lg);letter-spacing:-.02em;text-transform:lowercase;color:var(--ink);align-self:flex-start;align-items:baseline;gap:2px;font-weight:700;text-decoration:none;display:inline-flex}._brandMark_1rs5g_50{background:var(--accent);border-radius:1px;width:6px;height:6px}._projects_1rs5g_57{flex-direction:column;gap:2px;margin:0;padding:0;list-style:none;display:flex}._row_1rs5g_66{--row-gap:var(--space-2);align-items:center;gap:var(--row-gap);padding:6px var(--space-2);border-radius:var(--radius-control);color:var(--ink-muted);transition:background var(--duration) var(--ease-out), color var(--duration) var(--ease-out);flex-wrap:wrap;display:flex}._scope_1rs5g_78{flex-direction:column;gap:2px;display:flex}._scopeRow_1rs5g_84{color:var(--ink)}._scopeCurrent_1rs5g_88{background:var(--surface-selected);font-weight:600}._scopeName_1rs5g_93{font-weight:600}._scopeNote_1rs5g_97{padding:0 var(--space-2) 0 calc(var(--space-2) + 24px + var(--space-2));color:var(--ink-subtle);font-size:var(--text-sm);margin:0}._graphNotes_1rs5g_104{flex-direction:column;margin:auto 0 0;display:flex}._graphNote_1rs5g_104{gap:var(--space-1);padding:var(--space-2);color:var(--ink-subtle);font-size:var(--text-sm);flex-direction:column;margin:0;display:flex}._graphNote_1rs5g_104 code{overflow-wrap:anywhere}._disclosure_1rs5g_124{border-radius:var(--radius-chip);width:24px;height:24px;color:var(--ink-muted);cursor:pointer;background:0 0;border:0;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}._muted_1rs5g_139 ._projectName_1rs5g_139,._muted_1rs5g_139 ._count_1rs5g_140{color:var(--ink-subtle)}._number_1rs5g_144{font-variant-numeric:tabular-nums}._row_1rs5g_66:hover{background:var(--surface-hover);color:var(--ink)}._row_1rs5g_66:has(a[aria-current=true]){background:var(--surface-selected);color:var(--ink);font-weight:600}._scopeRow_1rs5g_84:hover{background:var(--surface-hover)}._rowLink_1rs5g_163{min-width:0;color:inherit;flex:1;text-decoration:none}._project_1rs5g_57{justify-content:space-between;align-items:center;gap:var(--space-2);padding:6px var(--space-2);border-radius:var(--radius-control);color:var(--ink-muted);transition:background var(--duration) var(--ease-out), color var(--duration) var(--ease-out);text-decoration:none;display:flex}._project_1rs5g_57:hover{background:var(--surface-hover);color:var(--ink)}._projectActive_1rs5g_187{background:var(--surface-selected);color:var(--ink);font-weight:600}._projectName_1rs5g_139{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}._count_1rs5g_140{font-size:var(--text-sm);font-variant-numeric:tabular-nums;color:var(--ink-subtle)}._signalCount_1rs5g_205{color:var(--warn);font-weight:600}@media (width<=900px){._shell_1rs5g_18{--main-overflow:visible;grid-template-rows:auto 1fr;grid-template-columns:minmax(0,1fr);height:auto;min-height:100%}._sidebar_1rs5g_26{align-items:center;gap:var(--space-2);border-right:none;border-bottom:1px solid var(--line);flex-flow:wrap;overflow-y:visible}._projects_1rs5g_57{--project-error-indent:0;align-items:flex-start;gap:var(--space-2);flex-flow:wrap}}._wrap_1nio7_1{align-items:center;gap:var(--space-2);display:flex}._track_1nio7_7{background:var(--line);border-radius:2px;flex:1;min-width:48px;height:4px;overflow:hidden}._fill_1nio7_16{background:var(--ink-subtle);transform-origin:0;width:100%;height:100%;transition:transform var(--duration) var(--ease-out);display:block}._value_1nio7_25{font-size:var(--text-sm);font-variant-numeric:tabular-nums;color:var(--ink-muted);white-space:nowrap}._lastDay_1nio7_32 ._fill_1nio7_16{background:var(--accent)}._lastDay_1nio7_32 ._value_1nio7_25{color:var(--accent-ink)}._bar_1nio7_40{vertical-align:text-bottom;background:var(--line);border-radius:2px;flex:none;width:3px;height:1.1em;display:inline-block;overflow:hidden}._barFill_1nio7_51{background:var(--ink-subtle);transform-origin:bottom;width:100%;height:100%;display:block}._lastDay_1nio7_32._bar_1nio7_40{background:var(--accent-soft)}._lastDay_1nio7_32 ._barFill_1nio7_51{background:var(--accent)}._wrap_1cpve_1{align-items:center;gap:var(--space-2);display:flex}._track_1cpve_7{background:var(--line);border-radius:2px;flex:1;min-width:48px;height:4px;overflow:hidden}._fill_1cpve_16{background:var(--ink-subtle);transform-origin:0;width:100%;height:100%;transition:transform var(--duration) var(--ease-out);display:block}._value_1cpve_25{min-width:34px;font-size:var(--text-sm);font-variant-numeric:tabular-nums;color:var(--ink-muted);text-align:right}._done_1cpve_33 ._fill_1cpve_16{background:var(--ok)}._drawer_1m3ig_1{--drawer-pad-block-start:var(--space-4);gap:var(--space-4);width:var(--panel-width);min-height:0;padding:var(--drawer-pad-block-start) var(--space-5) var(--space-6);border-left:1px solid var(--line);background:var(--surface-raised);overflow-wrap:anywhere;flex-direction:column;display:flex;overflow-y:auto}._drawer_1m3ig_1:focus{outline:none}@media (width<=1160px){._drawer_1m3ig_1{z-index:var(--z-panel);width:min(var(--panel-width), 100%);box-shadow:var(--shadow-panel), 0 0 0 100vmax var(--scrim);overscroll-behavior:contain;position:fixed;inset:0 0 0 auto}html:has(._drawer_1m3ig_1){overflow:hidden}}._header_1m3ig_34{justify-content:space-between;align-items:center;gap:var(--space-3);display:flex}._close_1m3ig_41{border-radius:var(--radius-chip);min-width:24px;min-height:24px;color:var(--ink-subtle);cursor:pointer;background:0 0;border:none;flex-shrink:0;place-items:center;padding:0;display:inline-grid}._close_1m3ig_41:hover{color:var(--ink)}._badge_xxffe_1{font-size:var(--text-sm);color:var(--ink-muted);white-space:nowrap;align-items:center;gap:6px;display:inline-flex}._dot_xxffe_10{background:var(--ink-subtle);border-radius:50%;width:7px;height:7px}._backlog_xxffe_17 ._dot_xxffe_10{background:var(--ink-subtle)}._inProgress_xxffe_21 ._dot_xxffe_10{background:var(--ink)}._blocked_xxffe_25 ._dot_xxffe_10{background:var(--warn)}._done_xxffe_29 ._dot_xxffe_10{background:var(--ok)}._cancelled_xxffe_33{color:var(--ink-subtle);text-decoration:line-through}._body_jt1t9_1{gap:var(--space-3);flex-direction:column;display:flex}._markdown_jt1t9_7{max-width:70ch;color:var(--ink);line-height:1.55}._markdown_jt1t9_7 h1,._markdown_jt1t9_7 h2,._markdown_jt1t9_7 h3{margin:var(--space-4) 0 var(--space-2);font-size:var(--text-md);text-wrap:balance;font-weight:600}._markdown_jt1t9_7 p,._markdown_jt1t9_7 ul,._markdown_jt1t9_7 ol{margin:0 0 var(--space-3);text-wrap:pretty}._markdown_jt1t9_7 ul{padding-left:var(--space-4)}._checkItem_jt1t9_33{margin-left:calc(var(--space-4) * -1);list-style:none}._checkItem_jt1t9_33 label{align-items:baseline;gap:var(--space-2);padding:2px var(--space-2);border-radius:var(--radius-chip);cursor:pointer;transition:background var(--duration) var(--ease-out);display:flex}._checkItem_jt1t9_33 label:hover{background:var(--surface-hover)}._checkItem_jt1t9_33 input:checked+span{color:var(--ink-muted)}._markdown_jt1t9_7 a{color:var(--ink);-webkit-text-decoration-color:var(--ink-subtle);text-decoration-color:var(--ink-subtle);text-underline-offset:2px}._markdown_jt1t9_7 a:hover{color:var(--accent-ink);text-decoration-color:currentColor}._markdown_jt1t9_7 pre{padding:var(--space-3);border-radius:var(--radius-control);background:var(--surface-sunken);font-size:var(--text-sm);overflow-x:auto}._tableScroll_jt1t9_75{margin:0 0 var(--space-3);overflow-wrap:normal;overflow-x:auto}._editor_jt1t9_81{gap:var(--space-2);flex-direction:column;display:flex}._editor_jt1t9_81 textarea{width:100%;padding:var(--space-3);font-family:var(--font-mono);font-size:var(--text-sm)}._editorActions_jt1t9_94{gap:var(--space-2);display:flex}._edit_jt1t9_81{align-self:flex-start}._grid_g41r9_1{gap:var(--space-3);grid-template-columns:repeat(auto-fit,minmax(min(100%,10.5rem),1fr));display:grid}._grid_g41r9_1 label,._tags_g41r9_8{gap:var(--space-1);font-size:var(--text-sm);color:var(--ink-subtle);flex-direction:column;display:flex}._grid_g41r9_1 :is(select,input),._tags_g41r9_8 input{font-size:var(--text-base)}._fieldError_g41r9_21{color:var(--danger-ink);font-size:var(--text-sm)}._section_102zu_1{gap:var(--space-2);flex-direction:column;display:flex}._heading_102zu_7{color:var(--ink-subtle);font-size:var(--text-sm);margin:0;font-weight:500}._items_102zu_14{gap:var(--space-1);flex-direction:column;margin:0;padding:0;list-style:none;display:flex}._item_102zu_14{align-items:baseline;gap:var(--space-2);font-size:var(--text-sm);display:flex}._id_102zu_30{font-family:var(--font-mono);color:var(--ink-muted)}._title_102zu_35{min-width:0;color:var(--ink);flex:1;text-decoration:none}a._title_102zu_35:hover{text-underline-offset:2px;text-decoration:underline}._remove_102zu_47{border-radius:var(--radius-chip);min-width:24px;min-height:24px;color:var(--ink-subtle);cursor:pointer;background:0 0;border:none;place-items:center;padding:0;display:inline-grid}._remove_102zu_47:hover{color:var(--danger-ink)}._add_102zu_64{gap:var(--space-2);display:flex}._add_102zu_64 input{flex:1;min-width:0}._fieldError_102zu_74{color:var(--danger-ink);font-size:var(--text-sm)}._id_14k85_1{font-family:var(--font-mono);font-size:var(--text-sm);color:var(--ink-muted)}._id_14k85_1[data-epic-tone]{padding:1px var(--space-2);border-radius:var(--radius-chip);background:var(--tone-soft);box-shadow:inset 3px 0 0 var(--tone-line);color:var(--tone-ink)}._title_14k85_15{width:100%;padding:var(--space-2);margin-left:calc(var(--space-2) * -1);font-size:var(--text-lg);resize:none;background:0 0;border-color:#0000;flex-shrink:0;font-weight:600;display:block;overflow:hidden}._title_14k85_15:hover{border-color:var(--line)}._title_14k85_15:focus{border-color:var(--line-strong);background:var(--surface)}._meta_14k85_38{align-items:center;gap:var(--space-3);font-size:var(--text-sm);color:var(--ink-subtle);flex-wrap:wrap;display:flex}._source_14k85_47{font-family:var(--font-mono)}._closure_14k85_51{gap:var(--space-2);padding:var(--space-3);border:1px solid var(--line);border-radius:var(--radius-control);background:var(--surface-sunken);font-size:var(--text-sm);color:var(--ink-muted);flex-direction:column;display:flex}._closure_14k85_51 p{margin:0}._restore_14k85_67{align-self:flex-start}._conflict_14k85_71{padding:var(--space-2) var(--space-3);border:1px solid var(--danger-line);border-radius:var(--radius-control);background:var(--danger-soft);color:var(--danger-ink);margin:0}._warnings_14k85_80{padding:var(--space-2) var(--space-3) var(--space-2) var(--space-5);border:1px solid var(--warn);border-radius:var(--radius-control);background:var(--warn-soft);color:var(--ink);margin:0}._readonlyRefs_14k85_89 h2{margin:0 0 var(--space-2);color:var(--ink);font-size:var(--text-sm);font-weight:600}._readonlyRefs_14k85_89 ul{gap:var(--space-1);font-size:var(--text-sm);flex-direction:column;margin:0;padding:0;list-style:none;display:flex}._refLink_14k85_106{color:var(--ink);text-decoration:none}._refClosed_14k85_111 ._refLink_14k85_106{color:var(--ink-subtle)}._refLink_14k85_106:hover{text-underline-offset:2px;text-decoration:underline}._saving_14k85_120{min-height:1lh;color:var(--ink-subtle);font-size:var(--text-sm);flex-shrink:0;margin:0}._saving_14k85_120:not(:empty),._conflict_14k85_71{top:calc(var(--drawer-pad-block-start) * -1);z-index:1;position:sticky}._saving_14k85_120:not(:empty){background:var(--surface-raised);box-shadow:0 var(--space-2) 0 var(--surface-raised), 0 calc(var(--space-2) + 1px) 0 var(--line)}:has(>._conflict_14k85_71){scroll-padding-top:calc(4lh + var(--space-4))}._chip_36904_1{padding:3px var(--space-2);border:1px solid var(--line-strong);border-radius:var(--radius-chip);background:var(--surface);color:var(--ink-muted);font-size:var(--text-sm);font-variant-numeric:tabular-nums;white-space:nowrap;cursor:pointer;transition:background var(--duration) var(--ease-out), border-color var(--duration) var(--ease-out), color var(--duration) var(--ease-out), scale var(--duration) var(--ease-out);align-items:center;display:inline-flex}._chip_36904_1:not(._static_36904_17,[aria-disabled=true]):active{scale:.96}._chip_36904_1:not(._static_36904_17,[aria-disabled=true]):hover{border-color:var(--ink-subtle);color:var(--ink)}._pressed_36904_26{border-color:var(--line-strong);background:var(--surface-selected);color:var(--ink);font-weight:600}._chip_36904_1[aria-disabled=true]{cursor:not-allowed}._label_36904_37{display:inline-grid}._text_36904_41{grid-area:1/1}._label_36904_37:after{content:attr(data-bold-width);visibility:hidden;grid-area:1/1;height:0;font-weight:600}._static_36904_17{cursor:default}._anchor_uubtj_1{min-width:0;max-width:100%;display:inline-flex;position:relative}._panel_uubtj_8{top:calc(100% + var(--space-1));z-index:var(--z-dropdown);width:min(420px, calc(100vw - 2 * var(--space-4)));max-height:min(360px,60vh);padding:var(--space-2);border:1px solid var(--line);border-radius:calc(var(--radius-chip) + var(--space-2));background:var(--surface-raised);box-shadow:var(--shadow-panel);flex-direction:column;display:flex;position:absolute;left:0;overflow:hidden}._selection_17l9i_1{align-items:center;gap:var(--space-1);min-width:0;max-width:100%;display:inline-flex}._toggle_17l9i_9{align-items:center;gap:var(--space-2);min-width:0;max-width:320px;display:inline-flex}._chosenTitle_17l9i_17{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}._dot_17l9i_23{background:var(--tone-line,var(--ink-subtle));border-radius:50%;flex:none;width:8px;height:8px}._reset_17l9i_31{min-width:24px;min-height:24px;color:var(--ink-subtle);cursor:pointer;background:0 0;border:none;place-items:center;display:inline-grid}._reset_17l9i_31:hover{color:var(--ink)}._options_17l9i_46{flex-direction:column;gap:2px;min-height:0;display:flex;overflow-y:auto}._options_17l9i_46 :focus-visible{outline-offset:-2px}._option_17l9i_46{align-items:center;gap:var(--space-2);min-height:32px;padding:var(--space-1) var(--space-2);border-radius:var(--radius-chip);color:var(--ink-muted);font:inherit;font-size:var(--text-base);text-align:left;cursor:pointer;background:0 0;border:none;display:flex}._option_17l9i_46:hover{background:var(--surface-hover);color:var(--ink)}._pressed_17l9i_79{background:var(--surface-selected);color:var(--ink);font-weight:600}._epics_17l9i_85{margin-top:var(--space-1);padding-top:var(--space-1);border-top:1px solid var(--line);flex-direction:column;gap:2px;display:flex}._id_17l9i_94{font-family:var(--font-mono);font-size:var(--text-sm);color:var(--ink-subtle)}._title_17l9i_100{flex:1;min-width:0}._count_17l9i_105{color:var(--ink-subtle);font-size:var(--text-sm);font-variant-numeric:tabular-nums;margin-left:auto}._toolbar_16bwi_1{gap:var(--space-4);padding:var(--space-3) var(--space-5);border-bottom:1px solid var(--line);flex-direction:column;display:flex}._line_16bwi_9{align-items:center;gap:var(--space-2) var(--space-3);flex-wrap:wrap;display:flex}._search_16bwi_16{flex:1;min-width:220px}._group_16bwi_21{align-items:center;gap:var(--space-1);flex-wrap:wrap;display:flex}._tagPicker_16bwi_28{align-items:center;gap:var(--space-1);flex-wrap:wrap;min-width:0;display:flex}._tagSearch_16bwi_36{margin-bottom:var(--space-2);flex:none}._tagOptions_16bwi_41{gap:var(--space-1);flex-wrap:wrap;min-height:0;display:flex;overflow-y:auto}._tagOptions_16bwi_41 :focus-visible{outline-offset:-2px}._count_16bwi_53{color:var(--ink-subtle)}._cell_rjack_1{gap:var(--space-1);flex-wrap:wrap;width:200px;display:flex;position:relative;overflow:clip}._cell_rjack_1 :focus-visible{outline-offset:-2px}._more_rjack_14{padding:3px var(--space-2);border:1px solid var(--line);border-radius:var(--radius-chip);background:var(--surface);color:var(--ink-muted);font:inherit;font-size:var(--text-sm);white-space:nowrap;cursor:pointer}._more_rjack_14:hover{border-color:var(--line-strong);color:var(--ink)}._ruler_rjack_31{visibility:hidden;pointer-events:none;display:flex;position:absolute;top:0;left:0}._rulerTags_rjack_40{display:flex}._table_1tmcn_1{border-collapse:collapse;width:100%;font-size:var(--text-base)}._table_1tmcn_1 thead th{z-index:1;padding:var(--space-2) var(--space-3);border-bottom:1px solid var(--line);background:var(--surface);color:var(--ink-subtle);font-size:var(--text-sm);text-align:left;white-space:nowrap;font-weight:500;position:sticky;top:0}._table_1tmcn_1 td{padding:var(--space-2) var(--space-3);border-bottom:1px solid var(--line);vertical-align:middle}._sortButton_1tmcn_27{align-items:center;gap:var(--space-1);color:inherit;font:inherit;cursor:pointer;background:0 0;border:none;padding:0;display:inline-flex}._sortButton_1tmcn_27:hover,._sorted_1tmcn_40{color:var(--ink)}._sortMark_1tmcn_44{min-width:1ch}._row_1tmcn_48:hover td{background:var(--surface-hover)}._selected_1tmcn_52 td{background:var(--surface-selected)}._id_1tmcn_56{font-family:var(--font-mono);font-size:var(--text-sm);color:var(--ink-muted);white-space:nowrap;text-decoration:none}._id_1tmcn_56:hover{color:var(--accent-ink)}._title_1tmcn_68{color:var(--ink);overflow-wrap:anywhere;text-decoration:none}._title_1tmcn_68:hover{text-underline-offset:2px;text-decoration:underline}._newBadge_1tmcn_79{margin-right:var(--space-2);border-radius:var(--radius-chip);background:var(--ink);color:var(--ink-inverse);font-size:var(--text-sm);white-space:nowrap;padding:1px 6px;font-weight:600;display:inline-block}._marker_1tmcn_91{margin-left:var(--space-2);border:1px solid var(--line);border-radius:var(--radius-chip);color:var(--ink-subtle);font-size:var(--text-sm);white-space:nowrap;padding:1px 6px;display:inline-block}._row_1tmcn_48[data-epic-tone] td:first-child{box-shadow:inset 3px 0 0 var(--tone-line)}._row_1tmcn_48[data-epic-tone] ._epicMarker_1tmcn_106{background:var(--tone-soft);color:var(--tone-ink);border-color:#0000}._priorityCell_1tmcn_112{white-space:nowrap}._low_1tmcn_116{color:var(--ink-subtle)}._medium_1tmcn_120{color:var(--ink-muted)}._high_1tmcn_124{color:var(--ink)}._critical_1tmcn_128{color:var(--accent-ink);font-weight:600}._date_1tmcn_133{color:var(--ink-subtle);font-variant-numeric:tabular-nums;white-space:nowrap}@container (width<=940px){td._tags_1tmcn_140,th._tags_1tmcn_140,._date_1tmcn_133{display:none}}@container (width<=700px){._priorityCell_1tmcn_112{display:none}}._table_1tmcn_1 th:first-child,._table_1tmcn_1 td:first-child{padding-inline-start:var(--space-5)}._table_1tmcn_1 ._date_1tmcn_133{padding-inline-end:var(--space-5)}@container (width<=940px){._table_1tmcn_1 ._priorityCell_1tmcn_112{padding-inline-end:var(--space-5)}}@container (width<=700px){._table_1tmcn_1 ._statusCell_1tmcn_169{padding-inline-end:var(--space-5)}}@container (width<=480px){._title_1tmcn_68{-webkit-hyphens:auto;hyphens:auto;hyphenate-limit-chars:12 5 5}._marker_1tmcn_91{white-space:normal}._table_1tmcn_1 th:first-child,._table_1tmcn_1 td:first-child{padding-inline-start:var(--space-3)}._table_1tmcn_1 ._statusCell_1tmcn_169{padding-inline-end:var(--space-3)}}._page_11yau_1{min-height:0;overflow:var(--main-overflow,hidden);grid-template-columns:minmax(0,1fr) auto;display:grid}._list_11yau_8{min-width:0;overflow-y:var(--main-overflow,auto);flex-direction:column;display:flex;container-type:inline-size}._heading_11yau_16{padding:var(--space-4) var(--space-5) 0;font-size:var(--text-lg);text-wrap:balance;margin:0;font-weight:600}._tableWrap_11yau_24{padding-bottom:var(--space-6)}._hint_11yau_28{max-width:60ch;margin:var(--space-6) var(--space-5);color:var(--ink-muted)}._hint_11yau_28 p{margin:0 0 var(--space-3)}._warning_11yau_38{margin:var(--space-3) var(--space-5) 0;padding:var(--space-3) var(--space-4);border:1px solid var(--warn);border-radius:var(--radius-control);background:var(--warn-soft);color:var(--ink)}._warning_11yau_38 ul{margin:var(--space-2) 0 0;padding-left:var(--space-4)}._crash_1hdjj_1{max-width:60ch;margin:var(--space-6) var(--space-5)}._crash_1hdjj_1 h1{font-size:var(--text-lg);font-weight:600}:root{--surface:oklch(25% 0 0);--surface-sunken:oklch(21.5% 0 0);--surface-raised:oklch(29% 0 0);--surface-hover:oklch(31% 0 0);--surface-selected:oklch(35% 0 0);--ink:oklch(94% 0 0);--ink-muted:oklch(80% 0 0);--ink-subtle:oklch(73% 0 0);--ink-inverse:oklch(20% 0 0);--line:oklch(36% 0 0);--line-strong:oklch(58% 0 0);--accent:oklch(66% .16 27.2);--accent-hover:oklch(72% .15 27.2);--accent-soft:oklch(35% .06 27.2);--accent-ink:oklch(76% .13 27.2);--danger-line:oklch(66% .16 27.2);--danger-ink:oklch(76% .13 27.2);--danger-soft:oklch(35% .06 27.2);--focus-ring:oklch(66% .16 27.2);--action:oklch(94% 0 0);--action-hover:oklch(100% 0 0);--warn:oklch(76% .12 75);--warn-soft:oklch(33% .05 75);--ok:oklch(74% .1 152);--ok-soft:oklch(31% .04 152);--epic-tone-1-line:oklch(70% .13 300);--epic-tone-1-ink:oklch(82% .1 300);--epic-tone-1-soft:oklch(34% .06 300);--epic-tone-2-line:oklch(70% .13 250);--epic-tone-2-ink:oklch(82% .09 250);--epic-tone-2-soft:oklch(34% .06 250);--epic-tone-3-line:oklch(70% .115 200);--epic-tone-3-ink:oklch(82% .1 200);--epic-tone-3-soft:oklch(34% .055 200);--epic-tone-4-line:oklch(70% .13 340);--epic-tone-4-ink:oklch(82% .1 340);--epic-tone-4-soft:oklch(34% .06 340);--epic-tone-5-line:oklch(70% .13 115);--epic-tone-5-ink:oklch(82% .1 115);--epic-tone-5-soft:oklch(34% .06 115);--chart-bar-warm:oklch(60% .11 27.2);--chart-bar-neutral:oklch(54% 0 0);--chart-bar-green:oklch(60% .09 152);--chart-line-green:oklch(86% .15 152);--chart-line-yellow:oklch(88% .14 90);--chart-line-blue:oklch(80% .11 250);--chart-line-bright:oklch(96% 0 0);--panel-width:420px;--radius-chip:4px;--radius-control:6px;--radius-panel:10px;--space-1:4px;--space-2:8px;--space-3:12px;--space-4:16px;--space-5:24px;--space-6:32px;--text-sm:.75rem;--text-base:.875rem;--text-md:1rem;--text-lg:1.125rem;--text-xl:1.375rem;--font-ui:system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;--font-mono:ui-monospace, SFMono-Regular, Menlo, monospace;--shadow-panel:0 1px 2px oklch(0% 0 0/.4), 0 8px 24px oklch(0% 0 0/.35);--shadow-dialog:0 24px 60px oklch(0% 0 0/.5);--scrim:oklch(0% 0 0/.5);--z-dropdown:10;--z-panel:20;--z-dialog:30;--ease-out:cubic-bezier(.22, 1, .36, 1);--duration:.16s;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}*,:before,:after{box-sizing:border-box}html,body,#root{height:100%}body{background:var(--surface);color:var(--ink);font-family:var(--font-ui);font-size:var(--text-base);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;margin:0;line-height:1.45}button,input,select,textarea{font:inherit;color:inherit}input,select,textarea{padding:6px var(--space-2);border:1px solid var(--line-strong);border-radius:var(--radius-control);background:var(--surface);color:var(--ink)}input[type=checkbox]{accent-color:var(--accent);padding:0}textarea{resize:vertical}code{font-family:var(--font-mono)}.inline-code{border-radius:var(--radius-chip);background:var(--surface-sunken);font-size:var(--text-sm);padding:1px 4px}::placeholder{color:var(--ink-subtle)}:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}.visually-hidden{clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}@media (prefers-reduced-motion:reduce){*,:before,:after{transition-duration:.01ms!important;animation-duration:.01ms!important}}[data-epic-tone="1"]{--tone-line:var(--epic-tone-1-line);--tone-ink:var(--epic-tone-1-ink);--tone-soft:var(--epic-tone-1-soft)}[data-epic-tone="2"]{--tone-line:var(--epic-tone-2-line);--tone-ink:var(--epic-tone-2-ink);--tone-soft:var(--epic-tone-2-soft)}[data-epic-tone="3"]{--tone-line:var(--epic-tone-3-line);--tone-ink:var(--epic-tone-3-ink);--tone-soft:var(--epic-tone-3-soft)}[data-epic-tone="4"]{--tone-line:var(--epic-tone-4-line);--tone-ink:var(--epic-tone-4-ink);--tone-soft:var(--epic-tone-4-soft)}[data-epic-tone="5"]{--tone-line:var(--epic-tone-5-line);--tone-ink:var(--epic-tone-5-ink);--tone-soft:var(--epic-tone-5-soft)}
@@ -0,0 +1 @@
1
+ var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),s=(e,n)=>{let r={};for(var i in e)t(r,i,{get:e[i],enumerable:!0});return n||t(r,Symbol.toStringTag,{value:`Module`}),r},c=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},l=(n,r,o)=>(o=n==null?{}:e(i(n)),c(r||!n||!n.__esModule||!a.call(n,`default`)?t(o,`default`,{value:n,enumerable:!0}):o,n));export{s as n,l as r,o as t};
@@ -0,0 +1 @@
1
+ import{r as e}from"./rolldown-runtime-hePW80VL.js";import{_n as t,vn as n}from"./i18n-BO0kwLac.js";import{$ as r,B as i,C as a,Ct as o,Dt as s,E as c,Et as l,F as u,I as d,K as f,L as p,M as m,N as h,O as g,Ot as _,P as v,Q as y,R as b,St as x,T as S,Tt as C,U as w,V as T,W as ee,Y as E,at as te,b as ne,bt as D,ct as re,et as ie,ft as O,gt as k,ht as A,it as j,k as ae,lt as M,mt as N,ot as oe,p as se,pt as ce,q as le,rt as ue,tt as de,ut as fe,w as pe,wt as me,x as he,xt as ge,y as _e,yt as P}from"./ChartTooltip-BYCfK3J2.js";var F=e(n());function I(){return I=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)({}).hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},I.apply(null,arguments)}var L=e=>{var t=e.cx,n=e.cy,r=e.r,i=e.className,a=_(`recharts-dot`,i);return D(t)&&D(n)&&D(r)?F.createElement(`circle`,I({},l(e),A(e),{className:a,cx:t,cy:n,r})):null},ve=[`points`];function R(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,r)}return n}function z(e){for(var t=1;t<arguments.length;t++){var n=arguments[t]==null?{}:arguments[t];t%2?R(Object(n),!0).forEach(function(t){ye(e,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):R(Object(n)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))})}return e}function ye(e,t,n){return(t=be(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function be(e){var t=xe(e,`string`);return typeof t==`symbol`?t:t+``}function xe(e,t){if(typeof e!=`object`||!e)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var r=n.call(e,t||`default`);if(typeof r!=`object`)return r;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(t===`string`?String:Number)(e)}function B(){return B=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)({}).hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},B.apply(null,arguments)}function Se(e,t){if(e==null)return{};var n,r,i=Ce(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)===-1&&{}.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function Ce(e,t){if(e==null)return{};var n={};for(var r in e)if({}.hasOwnProperty.call(e,r)){if(t.indexOf(r)!==-1)continue;n[r]=e[r]}return n}function we(e){var t=e.option,n=e.dotProps,r=e.className;if((0,F.isValidElement)(t))return(0,F.cloneElement)(t,n);if(typeof t==`function`)return t(n);var i=_(r,typeof t==`boolean`?``:t.className),a=n??{};a.points;var o=Se(a,ve);return F.createElement(L,B({},o,{className:i}))}function Te(e,t){return e==null?!1:t?!0:e.length===1}function V(e){var t=e.points,n=e.dot,r=e.className,i=e.dotClassName,a=e.dataKey,s=e.baseProps,c=e.needClip,l=e.clipPathId,u=e.zIndex,f=u===void 0?E.scatter:u;if(!Te(t,n))return null;var p=d(n),m=C(n),h=t.map((e,r)=>{var o=z(z(z({r:3},s),m),{},{index:r,cx:e.x??void 0,cy:e.y??void 0,dataKey:a,value:e.value,payload:e.payload,points:t});return F.createElement(we,{key:`dot-${r}`,option:n,dotProps:o,className:i})}),g={};return c&&l!=null&&(g.clipPath=`url(#clipPath-${p?``:`dots-`}${l})`),F.createElement(T,{zIndex:f},F.createElement(o,B({className:r},g),h))}function H(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,r)}return n}function U(e){for(var t=1;t<arguments.length;t++){var n=arguments[t]==null?{}:arguments[t];t%2?H(Object(n),!0).forEach(function(t){Ee(e,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):H(Object(n)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))})}return e}function Ee(e,t,n){return(t=De(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function De(e){var t=Oe(e,`string`);return typeof t==`symbol`?t:t+``}function Oe(e,t){if(typeof e!=`object`||!e)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var r=n.call(e,t||`default`);if(typeof r!=`object`)return r;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(t===`string`?String:Number)(e)}var ke=e=>{var t=e.point,n=e.childIndex,r=e.mainColor,i=e.activeDot,a=e.dataKey,c=e.clipPath;if(i===!1||t.x==null||t.y==null)return null;var l=U(U(U({},{index:n,dataKey:a,cx:t.x,cy:t.y,r:4,fill:r??`none`,strokeWidth:2,stroke:`#fff`,payload:t.payload,value:t.value}),s(i)),A(i)),u=(0,F.isValidElement)(i)?(0,F.cloneElement)(i,l):typeof i==`function`?i(l):F.createElement(L,l);return F.createElement(o,{className:`recharts-active-dot`,clipPath:c},u)};function W(e){var t=e.points,n=e.mainColor,r=e.activeDot,i=e.itemDataKey,o=e.clipPath,s=e.zIndex,c=s===void 0?E.activeDot:s,l=ce(w),u=a();if(t==null||u==null)return null;var d=t.find(e=>u.includes(e.payload));return P(d)?null:F.createElement(T,{zIndex:c},F.createElement(ke,{point:d,childIndex:Number(l),mainColor:n,dataKey:i,activeDot:r,clipPath:o}))}var Ae=[`animationElapsedTime`,`isAnimating`,`isEntrance`,`visibleLength`,`strokeDasharray`,`connectNulls`];function G(){return G=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)({}).hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},G.apply(null,arguments)}function je(e,t){if(e==null)return{};var n,r,i=Me(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)===-1&&{}.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function Me(e,t){if(e==null)return{};var n={};for(var r in e)if({}.hasOwnProperty.call(e,r)){if(t.indexOf(r)!==-1)continue;n[r]=e[r]}return n}function Ne(e){try{return e&&e.getTotalLength&&e.getTotalLength()||0}catch{return 0}}function K(e,t){return`${t}px ${e}px`}function Pe(e){return e.length%2==0?e:[...e,...e]}function Fe(e,t){for(var n=[],r=0;r<t;++r)n.push(...e);return n}function Ie(e,t,n){var r=Pe(n),i=r.reduce((e,t)=>e+t,0);if(!i)return K(t,e);for(var a=Math.floor(e/i),o=e%i,s=[],c=0,l=0;c<r.length;l+=(u=r[c])??0,++c){var u,d=r[c];if(d!=null&&l+d>o){s=[...r.slice(0,c),o-l];break}}var f=s.length%2==0?[0,t]:[t];return[...Fe(r,a),...s,...f].map(e=>`${e}px`).join(`, `)}function Le(e,t,n){return e?Ie(n,t,`${e}`.split(/[,\s]+/gim).map(e=>parseFloat(e))):K(t,n)}function Re(e){e.animationElapsedTime,e.isAnimating,e.isEntrance;var t=e.visibleLength,n=e.strokeDasharray,i=e.connectNulls,a=je(e,Ae),o=i??!1,s;if(t!=null){var c=a.pathRef;s=Le(n,Ne(c?.current??null),t)}else n!=null&&(s=String(n));return F.createElement(r,G({},a,{connectNulls:o,strokeDasharray:s}))}function ze(e){var t=(0,F.useRef)(0),n=(0,F.useRef)(0),r=(0,F.useRef)(!1),i=(0,F.useRef)(e);return i.current!==e&&(t.current=n.current,i.current=e),(0,F.useCallback)((e,i)=>{if(r.current)return null;var a=Math.min(x(t.current+e*i),i);return e>0&&i>0&&(n.current=Math.max(n.current,a),a>=i)?(r.current=!0,null):a},[])}var q=(e,t,n,r)=>ee(e,`xAxis`,t,r),J=(e,t,n,r)=>f(e,`xAxis`,t,r),Be=(e,t,n,r)=>ee(e,`yAxis`,n,r),Ve=(e,t,n,r)=>f(e,`yAxis`,n,r),He=O([de,q,Be,J,Ve],(e,t,n,r,i)=>fe(e,`xAxis`)?te(t,r,!1):te(n,i,!1)),Ue=(e,t,n,r,i)=>i;function We(e){return e.type===`line`}var Ge=O([le,Ue],(e,t)=>e.filter(We).find(e=>e.id===t)),Ke=O([de,q,Be,J,Ve,Ge,He,y],(e,t,n,r,i,a,o,s)=>{var c=s.chartData,l=s.dataStartIndex,u=s.dataEndIndex;if(!(a==null||t==null||n==null||r==null||i==null||r.length===0||i.length===0||o==null||e!==`horizontal`&&e!==`vertical`)){var d=a.dataKey,f=a.data,p=f!=null&&f.length>0?f:c?.slice(l,u+1);if(p!=null)return mt({layout:e,xAxis:t,yAxis:n,xAxisTicks:r,yAxisTicks:i,dataKey:d,bandSize:o,displayedData:p})}});function qe(e){var t=s(e),n=3,r=2;if(t!=null){var i=t.r,a=t.strokeWidth,o=Number(i),c=Number(a);return(Number.isNaN(o)||o<0)&&(o=n),(Number.isNaN(c)||c<0)&&(c=r),{r:o,strokeWidth:c}}return{r:n,strokeWidth:r}}var Je=[`id`],Ye=[`type`,`layout`,`connectNulls`,`needClip`,`shape`,`strokeDasharray`],Xe=[`activeDot`,`animateNewValues`,`animationBegin`,`animationDuration`,`animationEasing`,`connectNulls`,`dot`,`hide`,`isAnimationActive`,`label`,`legendType`,`xAxisId`,`yAxisId`,`id`];function Y(){return Y=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)({}).hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},Y.apply(null,arguments)}function X(e,t){if(e==null)return{};var n,r,i=Ze(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)===-1&&{}.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function Ze(e,t){if(e==null)return{};var n={};for(var r in e)if({}.hasOwnProperty.call(e,r)){if(t.indexOf(r)!==-1)continue;n[r]=e[r]}return n}function Qe(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,r)}return n}function Z(e){for(var t=1;t<arguments.length;t++){var n=arguments[t]==null?{}:arguments[t];t%2?Qe(Object(n),!0).forEach(function(t){$e(e,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):Qe(Object(n)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))})}return e}function $e(e,t,n){return(t=et(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function et(e){var t=tt(e,`string`);return typeof t==`symbol`?t:t+``}function tt(e,t){if(typeof e!=`object`||!e)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var r=n.call(e,t||`default`);if(typeof r!=`object`)return r;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(t===`string`?String:Number)(e)}function nt(e){try{return e&&e.getTotalLength&&e.getTotalLength()||0}catch{return 0}}function rt(e){var t=0,n=0;for(var r of e)r.status===`matched`&&r.prev.x!=null&&r.next.x!=null&&(t+=r.next.x-r.prev.x,n++);return n>0?t/n:0}var Q={activeDot:!0,animateNewValues:!0,animationBegin:0,animationDuration:1500,animationEasing:`ease`,animationInterpolateFn:(e,t)=>{if(e==null)return[];if(t===1)return e.flatMap(e=>e.status===`removed`?[]:[e.next]);var n=rt(e),r=[];for(var i of e)if(i.status===`matched`)r.push(Z(Z({},i.next),{},{x:k(i.prev.x,i.next.x,t),y:k(i.prev.y,i.next.y,t)}));else if(i.status===`added`){if(i.next.x!=null){var a=i.next.x-n;r.push(Z(Z({},i.next),{},{x:k(a,i.next.x,t),y:i.next.y}))}else r.push(i.next)}else if(i.status===`removed`&&i.prev.x!=null){var o=i.prev.x+n;r.push(Z(Z({},i.prev),{},{x:k(i.prev.x,o,t),y:i.prev.y}))}return r},animationMatchBy:m,connectNulls:!1,dot:!0,fill:`#fff`,hide:!1,isAnimationActive:`auto`,label:!1,legendType:`line`,shape:Re,stroke:`#3182bd`,strokeWidth:1,xAxisId:0,yAxisId:0,zIndex:E.line,type:`linear`},it=e=>{var t=e.dataKey,n=e.name,r=e.stroke,i=e.legendType;return[{inactive:e.hide,dataKey:t,type:i,color:r,value:re(n,t),payload:e}]},at=F.memo(e=>{var t=e.dataKey,n=e.data,r=e.stroke,i=e.strokeWidth,a=e.fill,o=e.name,s=e.hide,c=e.unit,l=e.formatter,u=e.tooltipType,d=e.id,f={dataDefinedOnItem:n,getPosition:ge,settings:{stroke:r,strokeWidth:i,fill:a,dataKey:t,nameKey:void 0,name:re(o,t),hide:s,type:u,color:r,unit:c,formatter:l,graphicalItemId:d}};return F.createElement(v,{tooltipEntrySettings:f})});function ot(e){var t=e.clipPathId,n=e.points,r=e.props,i=r.dot,a=r.dataKey,o=r.needClip;r.id;var s=X(r,Je),c=l(s);return F.createElement(V,{points:n,dot:i,className:`recharts-line-dots`,dotClassName:`recharts-line-dot`,dataKey:a,baseProps:c,needClip:o,clipPathId:t})}function st(e){var t=e.showLabels,n=e.children,r=e.points,i=(0,F.useMemo)(()=>r?.map(e=>{var t={x:e.x??0,y:e.y??0,width:0,lowerWidth:0,upperWidth:0,height:0};return Z(Z({},t),{},{value:e.value,payload:e.payload,viewBox:t,parentViewBox:void 0,fill:void 0})}),[r]);return F.createElement(p,{value:t?i:void 0},n)}function ct(e){var t=e.clipPathId,n=e.pathRef,r=e.points,i=e.props,a=e.animationElapsedTime,o=e.isAnimating,s=e.isEntrance,c=e.visibleLength,l=i.type,d=i.layout,f=i.connectNulls,p=i.needClip,m=i.shape,h=i.strokeDasharray,g=X(i,Ye),_=Z(Z({},me(g)),{},{fill:`none`,className:`recharts-line-curve`,clipPath:p?`url(#clipPath-${t})`:void 0,points:r,type:l,layout:d,connectNulls:f,strokeDasharray:h??i.strokeDasharray,pathRef:n,animationElapsedTime:a,isAnimating:o,isEntrance:i.animateNewValues?s:!1,visibleLength:c});return F.createElement(F.Fragment,null,r?.length>1&&F.createElement(u,{option:m,DefaultShape:Q.shape,shapeProps:_}),F.createElement(ot,{points:r,clipPathId:t,props:i}))}function lt(e){var t=e.clipPathId,n=e.props,r=e.pathRef,i=e.previousPointsRef,a=n.points,o=n.isAnimationActive,s=n.animationBegin,c=n.animationDuration,l=n.animationEasing,u=n.animationMatchBy,d=n.animationInterpolateFn,f=n.layout,p=nt(r.current),m=ae(n.onAnimationStart,n.onAnimationEnd),h=m.isAnimating,_=m.handleAnimationStart,v=m.handleAnimationEnd,y=!h,x=ze(a),S=(0,F.useCallback)(e=>e>0&&p>0,[p]);return F.createElement(st,{points:a,showLabels:y},n.children,F.createElement(g,{animationInput:a,animationIdPrefix:`recharts-line-`,items:a,previousItemsRef:i,isAnimationActive:o,animationBegin:s,animationDuration:c,animationEasing:l,onAnimationStart:_,onAnimationEnd:v,animationInterpolateFn:d,animationMatchBy:u,shouldUpdatePreviousRef:S,layout:f},(e,i,a)=>{var o=h||i<1,s=o?x(i,p):null;return F.createElement(ct,{props:n,points:e,clipPathId:t,pathRef:r,animationElapsedTime:i,isAnimating:o,isEntrance:a,visibleLength:s})}),F.createElement(b,{label:n.label}))}function ut(e){var t=e.clipPathId,n=e.props,r=(0,F.useRef)(null),i=(0,F.useRef)(null);return F.createElement(lt,{props:n,clipPathId:t,previousPointsRef:r,pathRef:i})}var dt=(e,t)=>({x:e.x??void 0,y:e.y??void 0,value:e.value,errorVal:M(e.payload,t)}),ft=class extends F.Component{render(){var e=this.props,t=e.hide,n=e.dot,r=e.points,i=e.className,a=e.xAxisId,s=e.yAxisId,c=e.top,l=e.left,u=e.width,f=e.height,p=e.id,m=e.needClip,h=e.zIndex;if(t)return null;var g=_(`recharts-line`,i),v=p,y=qe(n),b=y.r,x=y.strokeWidth,S=d(n),C=b*2+x,w=m?`url(#clipPath-${S?``:`dots-`}${v})`:void 0;return F.createElement(T,{zIndex:h},F.createElement(o,{className:g},m&&F.createElement(`defs`,null,F.createElement(_e,{clipPathId:v,xAxisId:a,yAxisId:s}),!S&&F.createElement(`clipPath`,{id:`clipPath-dots-${v}`},F.createElement(`rect`,{x:l-C/2,y:c-C/2,width:u+C,height:f+C}))),F.createElement(he,{xAxisId:a,yAxisId:s,data:r,dataPointFormatter:dt,errorBarOffset:0},F.createElement(ut,{props:this.props,clipPathId:v}))),F.createElement(W,{activeDot:this.props.activeDot,points:r,mainColor:this.props.stroke,itemDataKey:this.props.dataKey,clipPath:w}))}};function pt(e){var t=N(e,Q),n=t.activeDot,r=t.animateNewValues,i=t.animationBegin,a=t.animationDuration,o=t.animationEasing,s=t.connectNulls,c=t.dot,l=t.hide,u=t.isAnimationActive,d=t.label,f=t.legendType,p=t.xAxisId,m=t.yAxisId,h=t.id,g=X(t,Xe),_=ne(p,m).needClip,v=pe(),y=ue(),b=j(),x=ce(e=>Ke(e,p,m,b,h));if(y!==`horizontal`&&y!==`vertical`||x==null||v==null)return null;var S=v.height,C=v.width,w=v.x,T=v.y;return F.createElement(ft,Y({},g,{id:h,connectNulls:s,dot:c,activeDot:n,animateNewValues:r,animationBegin:i,animationDuration:a,animationEasing:o,isAnimationActive:u,hide:l,label:d,legendType:f,xAxisId:p,yAxisId:m,points:x,layout:y,height:S,width:C,left:w,top:T,needClip:_}))}function mt(e){var t=e.layout,n=e.xAxis,r=e.yAxis,i=e.xAxisTicks,a=e.yAxisTicks,o=e.dataKey,s=e.bandSize;return e.displayedData.map((e,c)=>{var l=M(e,o);if(t===`horizontal`)return{x:oe({axis:n,ticks:i,bandSize:s,entry:e,index:c}),y:(P(l)?null:r.scale.map(l))??null,value:l,payload:e};var u=P(l)?null:n.scale.map(l),d=oe({axis:r,ticks:a,bandSize:s,entry:e,index:c});return u==null||d==null?null:{x:u,y:d,value:l,payload:e}}).filter(Boolean)}function ht(e){var t=N(e,Q),n=j();return F.createElement(c,{id:t.id,type:`line`},e=>F.createElement(F.Fragment,null,F.createElement(h,{legendPayload:it(t)}),F.createElement(at,{dataKey:t.dataKey,data:t.data,stroke:t.stroke,strokeWidth:t.strokeWidth,fill:t.fill,name:t.name,hide:t.hide,unit:t.unit,formatter:t.formatter,tooltipType:t.tooltipType,id:e}),F.createElement(S,{type:`line`,id:e,data:t.data,xAxisId:t.xAxisId,yAxisId:t.yAxisId,zAxisId:0,dataKey:t.dataKey,hide:t.hide,isPanorama:n}),F.createElement(pt,Y({},t,{id:e}))))}var $=F.memo(ht,ie);$.displayName=`Line`;var gt=[`axis`],_t=(0,F.forwardRef)((e,t)=>F.createElement(se,{chartName:`ComposedChart`,defaultTooltipEventType:`axis`,validateTooltipEventTypes:gt,tooltipPayloadSearcher:i,categoricalChartProps:e,ref:t})),vt=t(),yt=3.5;function bt(e){return function({cx:t,cy:n,value:r,index:i}){return typeof r!=`number`||r===0||t===void 0||n===void 0?(0,vt.jsx)(`g`,{},i):(0,vt.jsx)(`circle`,{cx:t,cy:n,r:yt,fill:e,stroke:`var(--surface-raised)`,strokeWidth:1.5},i)}}export{W as a,qe as i,_t as n,V as o,$ as r,bt as t};
@@ -0,0 +1,16 @@
1
+ <!doctype html>
2
+ <html lang="ru">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>Backlog</title>
7
+ <script type="module" crossorigin src="/assets/index-C-8JzRpY.js"></script>
8
+ <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-hePW80VL.js">
9
+ <link rel="modulepreload" crossorigin href="/assets/i18n-BO0kwLac.js">
10
+ <link rel="stylesheet" crossorigin href="/assets/i18n-BlPq0Oql.css">
11
+ <link rel="stylesheet" crossorigin href="/assets/index-DyGLN1aL.css">
12
+ </head>
13
+ <body>
14
+ <div id="root"></div>
15
+ </body>
16
+ </html>
package/package.json ADDED
@@ -0,0 +1,90 @@
1
+ {
2
+ "name": "p-backlog",
3
+ "version": "0.2.0",
4
+ "description": "Personal developer backlog for Claude Code: tasks as Markdown files, CLI, Stop hook and a local web UI",
5
+ "keywords": [
6
+ "backlog",
7
+ "claude-code",
8
+ "cli",
9
+ "task-management",
10
+ "markdown"
11
+ ],
12
+ "homepage": "https://github.com/expatriate/p-backlog#readme",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/expatriate/p-backlog.git"
16
+ },
17
+ "bugs": {
18
+ "url": "https://github.com/expatriate/p-backlog/issues"
19
+ },
20
+ "license": "Apache-2.0",
21
+ "type": "module",
22
+ "engines": {
23
+ "node": ">=22.13"
24
+ },
25
+ "files": [
26
+ "dist/cli.js",
27
+ "dist/server.js",
28
+ "dist/web",
29
+ "skill",
30
+ "README.md",
31
+ "README.ru.md",
32
+ "CHANGELOG.md"
33
+ ],
34
+ "scripts": {
35
+ "test": "vitest run",
36
+ "lint": "eslint . && knip && node scripts/check-cyrillic.mjs",
37
+ "typecheck": "tsc -p tsconfig.json",
38
+ "build": "vite build && node scripts/build-node.mjs",
39
+ "install-skill": "node dist/cli.js setup",
40
+ "start": "npm run build && node dist/server.js",
41
+ "dev": "concurrently -k -n server,web \"tsx watch src/server/main.ts\" \"vite\"",
42
+ "test:e2e": "playwright test",
43
+ "test:package": "vitest run --config vitest.package.config.ts",
44
+ "prepare": "npm run build",
45
+ "test:coverage": "vitest run --coverage",
46
+ "knip": "knip"
47
+ },
48
+ "dependencies": {
49
+ "@hono/node-server": "^2.1.1",
50
+ "chokidar": "^5.0.0",
51
+ "hono": "^4.13.8",
52
+ "yaml": "^2.9.1",
53
+ "zod": "^4.6.5"
54
+ },
55
+ "devDependencies": {
56
+ "@eslint/js": "^10.0.1",
57
+ "@playwright/test": "^1.63.0",
58
+ "@tanstack/react-query": "^5.103.1",
59
+ "@testing-library/dom": "^10.4.2",
60
+ "@testing-library/react": "^16.3.3",
61
+ "@testing-library/user-event": "^14.6.7",
62
+ "@types/node": "^26.6.2",
63
+ "@types/react": "^19.3.0",
64
+ "@types/react-dom": "^19.3.0",
65
+ "@vitejs/plugin-react": "^6.1.1",
66
+ "@vitest/coverage-v8": "^5.0.1",
67
+ "concurrently": "^10.0.5",
68
+ "esbuild": "^0.28.2",
69
+ "eslint": "^10.11.0",
70
+ "eslint-plugin-react-hooks": "^7.1.1",
71
+ "globals": "^17.12.0",
72
+ "jsdom": "^30.1.0",
73
+ "knip": "^6.37.0",
74
+ "react": "^19.3.0",
75
+ "react-dom": "^19.3.0",
76
+ "react-is": "^19.3.0",
77
+ "react-markdown": "^10.1.0",
78
+ "react-router": "^8.4.0",
79
+ "recharts": "^3.10.1",
80
+ "remark-gfm": "^4.0.1",
81
+ "tsx": "^4.23.15",
82
+ "typescript": "~6.0.3",
83
+ "typescript-eslint": "^8.70.0",
84
+ "vite": "^8.3.0",
85
+ "vitest": "^5.0.1"
86
+ },
87
+ "bin": {
88
+ "backlog": "dist/cli.js"
89
+ }
90
+ }
@@ -0,0 +1,182 @@
1
+ ---
2
+ name: backlog
3
+ description: Use when, while working on code, you notice a problem outside the current task that deserves its own follow-up (bug, tech debt, missing test, risky TODO); when the user says «запиши в беклог», «заведи задачу», «что в беклоге»; when asked to take a backlog task — «возьми SPA-12», «возьми следующую задачу», "pick up the next task"; when asked to check or clean up the backlog — «проверь беклог», «почисти беклог»; or when a Stop hook message says the code of backlog tasks changed since their last check.
4
+ ---
5
+
6
+ # Беклог задач
7
+
8
+ Задачи — md-файлы в `~/backlog/<проект>/<ID>.md` (каталог переопределяется `BACKLOG_DIR`). Создание,
9
+ взятие в работу и смена статуса — только через CLI `backlog`: он выдаёт ID без коллизий, проверяет связи
10
+ и находит проект по текущему репозиторию. Файлы задач вручную не создавай и не переименовывай.
11
+
12
+ Если `backlog` не найден (`command not found`) — файлы сам не пиши. Скажи пользователю: «CLI backlog
13
+ не установлен: выполните `npm i -g p-backlog`».
14
+
15
+ ## Записать задачу
16
+
17
+ Записывай сам, не спрашивая пользователя, если замечание одновременно:
18
+
19
+ - **вне рамок** текущей работы — его исправление не входит в то, о чём просили;
20
+ - **конкретно** — есть `файл:строка` и понятно, что сломается или чем это грозит;
21
+ - **не чинится попутно**:
22
+ - то, что не меняет поведение и лежит в коде, который ты и так меняешь (опечатка, неиспользуемый импорт,
23
+ неточное имя), — просто исправь;
24
+ - баг, из-за которого код работает неправильно, — отдельная задача, даже если исправление в одну строку
25
+ и в том же файле: об изменении этого поведения не просили;
26
+ - если без исправления бага текущую задачу не сделать — исправь его в рамках задачи и прямо напиши
27
+ в ответе, какое поведение изменил и где (`файл:строка`).
28
+
29
+ Не записывай: вкусовые замечания без последствий, непроверенные догадки, то, что чинишь в этой же задаче.
30
+
31
+ 1. Проверь дубли по 2–3 ключевым словам сути проблемы:
32
+ ```bash
33
+ backlog list --query "таймаут загрузк"
34
+ ```
35
+ Есть открытая задача про то же — новую не создавай, упомяни существующий ID в итоговом ответе.
36
+
37
+ 2. Создай задачу. Описание передавай всегда через heredoc — без него команда ждёт stdin:
38
+ ```bash
39
+ backlog new --title "Таймаут загрузки не учитывает размер файла" \
40
+ --priority high --tags upload,network --source src/upload/client.ts:88 --category bug <<'EOF'
41
+ Таймаут фиксированный — 30 с, файлы больше ~500 МБ обрываются на медленном канале.
42
+
43
+ **Чем грозит:** большие файлы не загружаются, повторная попытка тоже падает.
44
+
45
+ **Как проверить:** загрузить файл 2 ГБ при троттлинге сети «Slow 3G» в DevTools.
46
+
47
+ ## Чеклист
48
+ - [ ] Считать таймаут от размера файла
49
+ - [ ] Тест на расчёт таймаута
50
+ EOF
51
+ ```
52
+ - `--title` — суть проблемы, а не действие: «Таймаут загрузки не учитывает размер файла», а не «Поправить таймаут».
53
+ - `--priority`: `critical` — ломает прод или данные; `high` — заметный пользователю баг; `medium` — долг, который мешает работе; `low` — улучшение.
54
+ - `--tags` — область кода и вид работы: `upload`, `auth`, `tech-debt`, `tests`.
55
+ - `--source` — где заметил, `файл:строка`.
56
+ - `--category` — обязательно. Запах кода — его категория из каталога code-smells: `bloaters`,
57
+ `change-preventers`, `couplers`, `data-dealers`, `dispensables`, `functional-abusers`,
58
+ `lexical-abusers`, `oo-abusers`, `obfuscators`. Неправильное поведение — `bug`.
59
+ - `--found review` — находка аудита или ревью по просьбе пользователя; замеченное попутно флага не
60
+ требует.
61
+ - Работаешь над задачей из беклога — добавь `--related <её ID>`.
62
+ - Чеклист — проверяемые шаги: по нему считается прогресс.
63
+ - Код выхода 3 и «Похоже на SPA-12 — …» — такая задача уже открыта: новую не создавай, упомяни
64
+ существующий ID в ответе. `--force` — только если это точно другая проблема.
65
+ - Несколько мелких находок одного ревью (уровня Minor: запахи, мелкие неточности) — **одной** задачей, а не
66
+ каждой отдельно: заголовок «Мелочи ревью: <что ревьюили>», в чеклисте по пункту на находку
67
+ (`- [ ] Magic Number — src/a.ts:42: что не так`), `--category` — самая частая категория среди находок,
68
+ `--source` — место первой. Отдельными задачами — только важные находки и баги.
69
+
70
+ 3. В конце ответа перечисли созданное отдельным блоком, который начинается строкой «Добавлено в беклог:» —
71
+ по ней пользователь находит новые задачи в длинном ответе:
72
+ ```
73
+ Добавлено в беклог:
74
+ - SPA-14 — Таймаут загрузки не учитывает размер файла
75
+ ```
76
+ Если CLI написал «Создан проект …» — добавь это одной строкой.
77
+
78
+ Несколько задач про одно — собрать их в эпик: создать эпик (`backlog new --type epic --title …`) и перенести
79
+ задачи `backlog epic <ID> [<ID> …] --to <ID эпика>`; `--to none` вынимает задачу из эпика. Эпик закрывается
80
+ сам, когда закрыты все его задачи.
81
+
82
+ ## Взять задачу в работу
83
+
84
+ «Возьми SPA-12» → `backlog take SPA-12`. «Возьми следующую» → `backlog take --next` (проект — по текущему
85
+ репозиторию; из другого каталога добавь `--project <id>`). «Возьми все задачи по src/web/stats» →
86
+ `backlog take --path src/web/stats`: берёт все открытые задачи, чей `source` внутри пути (заблокированные
87
+ пропускает), и печатает их подряд через `---` — исправляй их вместе, закрывай каждую.
88
+
89
+ | Код | Что случилось | Что делать |
90
+ |---|---|---|
91
+ | 0 | Статус стал `in-progress`, выведены путь, связи и текст задачи | Работать |
92
+ | 1 | Это эпик | Показать пользователю задачи эпика из вывода и спросить, какую взять |
93
+ | 2 | Задача или проект не найдены, открытых задач нет | Сообщить пользователю |
94
+ | 3 | Открытые блокеры или задача уже закрыта; при `--next` и `--path` — все подходящие задачи заблокированы | Перечислить блокеры и остановиться. `--force` — только по прямой просьбе пользователя |
95
+
96
+ 1. Прочитай описание и `source`; нужные связанные задачи — `backlog show <ID>`.
97
+ 2. Делай работу. Выполнил пункт чеклиста — сразу отметь его в файле задачи (`- [ ]` → `- [x]`, путь есть
98
+ в выводе `take`). Появились новые шаги — допиши их в чеклист. Frontmatter руками не меняй.
99
+ 3. Посторонние проблемы, найденные по ходу, — через «Записать задачу» с `--related <ID>`.
100
+ 4. Перед закрытием проверь результат командами проекта: тесты, линт, типы.
101
+ 5. Всё сделано, проверено и закоммичено → `backlog close <ID> --as fixed --reason "Исправлено в <sha>: <что
102
+ именно>"` — по хешу статистика узнаёт, кто и чем исправил. Коммита нет (правки ещё не закоммичены) →
103
+ `backlog status <ID> done`. Если CLI предупредил о неотмеченных пунктах —
104
+ отметь сделанные; если что-то не сделано, задача не закончена.
105
+ 6. Сделано не всё → статус оставь `in-progress`, допиши в конец файла задачи раздел и скажи пользователю,
106
+ что осталось:
107
+ ```markdown
108
+ ## Заметки
109
+ - <сегодняшняя дата>: сделано …; осталось …, потому что …
110
+ ```
111
+
112
+ ## Перепроверить задачи
113
+
114
+ Когда: сообщение хука «после последней проверки менялся код задач», просьба «проверь беклог» или
115
+ «почисти беклог».
116
+
117
+ 1. `backlog check --json` из репозитория проекта (из другого каталога — `--project <id>`). Висячие ссылки,
118
+ завершённые эпики и сдвинутые `source` он уже исправил сам — это поле `fixed`, список `{ kind, taskId, … }`:
119
+ `references-removed` — убраны ссылки на несуществующие задачи `ids`; `epic-closed` — эпик закрыт, все его
120
+ задачи `childIds` закрыты; `source-moved` — `source` сдвинулся `from` → `to`. Перескажи его пользователю
121
+ одной строкой.
122
+ 2. У кандидата `source-changed` в JSON уже есть `problem` — первый абзац описания задачи, `snippet` —
123
+ текущий код вокруг `source` с номерами строк — и `diff` — изменения файла с последней проверки (у
124
+ обрезанного `diffOmittedLines` — сколько строк не показано). Обычно этого хватает: реши по ним, не вызывая
125
+ `show`, `grep` и `git show`. Читай задачу (`backlog show <ID>`) и код целиком,
126
+ только если по `snippet` и `diff` не понять; у `duplicate` и `no-source` читай задачи всегда.
127
+ 3. Реши:
128
+
129
+ | Что видно в коде | Команда |
130
+ |---|---|
131
+ | Описанной проблемы больше нет | `backlog close <ID> --as fixed --reason "Исправлено в <sha>: <что именно>"` (без хеша существующего коммита CLI не закроет) |
132
+ | Кода или фичи, о которых задача, больше нет | `backlog close <ID> --as obsolete --reason "<что удалено и где>"` |
133
+ | `source-missing`: код переехал (подсказка — `renamedTo`), проблема на месте | `backlog verify <ID> --source <новый файл:строка>` |
134
+ | `source-missing`: кода, о котором задача, больше нет | `backlog close <ID> --as obsolete --reason "<что удалено и где>"` |
135
+ | `duplicate`: две задачи про одно | закрой менее полную: `backlog close <ID> --as duplicate --duplicate-of <другая> --reason "<в чём совпадают>"` |
136
+ | `duplicate`: задачи про разное | подтверди обе: `backlog verify <ID>` и `backlog verify <другая>` |
137
+ | Проблема на месте, но код сдвинулся | `backlog verify <ID> --source <файл:строка>` |
138
+ | Проблема на месте или уверенности нет | `backlog verify <ID>`; несколько сразу — `backlog verify <ID> <ID> …` |
139
+
140
+ Простой `backlog verify <ID>` не снимает `source-missing`: пропавший файл уходит из кандидатов только
141
+ с новым `--source` или закрытием, иначе хук будет напоминать о задаче после каждого ответа. Не нашёл,
142
+ куда делся код, — спроси пользователя. Пара `duplicate` уходит, только когда подтверждены обе задачи.
143
+
144
+ Закрывай только с конкретной уликой: коммит, строка, факт отсутствия кода. «Похоже, уже неактуально» —
145
+ не улика: подтверди задачу и оставь открытой. Закрытая задача через 7 дней удаляется вместе с файлом.
146
+
147
+ 4. `problems` — список `{ kind, … }`. `file-not-parsed`: файл `path` не разбирается, причины в `problems` —
148
+ поправь YAML руками, не меняя `id`. Остальное перечисли пользователю: `task-invalid` (ошибка `problem`
149
+ в задаче `taskId`), `fix-failed` (исправление не записалось, причина `cause`), `epics-wait-for-files`,
150
+ `project-without-repos`, `project-repos-missing`.
151
+ 5. В конце ответа — блок, по которому пользователь найдёт закрытое:
152
+ ```
153
+ Закрыто в беклоге:
154
+ - SPA-14 — Таймаут загрузки не учитывает размер файла: исправлено в a1b2c3d
155
+ ```
156
+ Подтверждённые задачи не перечисляй, достаточно «Остальные задачи подтверждены».
157
+
158
+ Если перепроверку запросил хук, после неё просто закончи ответ: второй раз подряд хук не срабатывает.
159
+
160
+ ## Разобрать застоявшиеся мелочи
161
+
162
+ Когда: тревога «Задач с низким приоритетом старше 30 дней» или просьба «разбери старые задачи».
163
+
164
+ 1. `backlog prune` — список задач с низким приоритетом старше 30 дней, которые не брали в работу. Ничего
165
+ не меняет.
166
+ 2. Покажи список пользователю и спроси, отменить ли их. Нужные задачи он может поднять в приоритете или
167
+ взять в работу.
168
+ 3. Только после явного согласия — `backlog prune --apply`: отменяет их как `obsolete`.
169
+
170
+ ## Посмотреть беклог
171
+
172
+ Проект, который больше не ведётся, помечается неактивным: `backlog project status <id> inactive` — его
173
+ задачи выпадают из общей области «Проекты» (список и статистика), но остаются доступны на странице проекта.
174
+ `backlog project list` показывает статусы. Удаление проекта (`backlog project delete <id> --confirm <id>`)
175
+ сносит каталог со всеми задачами — выполнять только по прямой просьбе пользователя.
176
+
177
+ «Что в беклоге» → `backlog list`: открытые задачи текущего проекта по приоритету. По запросу:
178
+ `--all-projects`, `--status done`, `--tag <тег>`, `--query <текст>`. Подробности — `backlog show <ID>`.
179
+
180
+ Сводка и тревоги — `backlog stats`.
181
+
182
+ Сменить категорию — `backlog category <ID> <категория|none>`. Сменить приоритет — `backlog priority <ID> <low|medium|high|critical>`.
@@ -0,0 +1,194 @@
1
+ ---
2
+ name: backlog
3
+ description: Use when, while working on code, you notice a problem outside the current task that deserves its own follow-up (bug, tech debt, missing test, risky TODO); when the user says "log this to the backlog", "add a task", "what's in the backlog"; when asked to take a backlog task — "take SPA-12", "take the next task", "pick up the next task"; when asked to check or clean up the backlog — "check the backlog", "clean up the backlog"; or when a Stop hook message says the code of backlog tasks changed since their last check.
4
+ ---
5
+
6
+ # Task Backlog
7
+
8
+ Tasks are markdown files at `~/backlog/<project>/<ID>.md` (the directory can be overridden with
9
+ `BACKLOG_DIR`). Creating tasks, taking them into progress, and changing their status all go through the
10
+ `backlog` CLI only: it hands out collision-free IDs, checks links, and finds the project from the current
11
+ repository. Never create or rename task files by hand.
12
+
13
+ If `backlog` is not found (`command not found`) — do not write task files yourself. Tell the user: "The
14
+ `backlog` CLI is not installed: run `npm i -g p-backlog`."
15
+
16
+ ## Log a task
17
+
18
+ Log it yourself, without asking the user, when a finding is all of the following at once:
19
+
20
+ - **out of scope** for the current work — fixing it isn't part of what was asked;
21
+ - **specific** — there's a `file:line` and it's clear what will break or what it risks;
22
+ - **not fixed in passing**:
23
+ - something that doesn't change behavior and sits in code you're already touching (a typo, an unused
24
+ import, an imprecise name) — just fix it;
25
+ - a bug that makes the code behave incorrectly — its own task, even if the fix is a one-line change in
26
+ the same file: changing that behavior isn't what was asked;
27
+ - if the current task can't be finished without fixing the bug — fix it as part of the task and say
28
+ plainly in your answer what behavior you changed and where (`file:line`).
29
+
30
+ Don't log: taste-only remarks with no consequences, unverified guesses, or anything you're fixing within
31
+ this same task.
32
+
33
+ 1. Check for duplicates by 2–3 keywords of the problem's essence:
34
+ ```bash
35
+ backlog list --query "upload timeout"
36
+ ```
37
+ If an open task about the same thing already exists, don't create a new one — mention the existing ID
38
+ in your final answer.
39
+
40
+ 2. Create the task. Always pass the description through a heredoc — without it the command waits on
41
+ stdin:
42
+ ```bash
43
+ backlog new --title "Upload timeout ignores file size" \
44
+ --priority high --tags upload,network --source src/upload/client.ts:88 --category bug <<'EOF'
45
+ The timeout is fixed at 30 s; files over ~500 MB drop on a slow connection.
46
+
47
+ **Impact:** large files fail to upload, and the retry fails too.
48
+
49
+ **How to check:** upload a 2 GB file with network throttling set to "Slow 3G" in DevTools.
50
+
51
+ ## Checklist
52
+ - [ ] Compute the timeout from file size
53
+ - [ ] Test for the timeout computation
54
+ EOF
55
+ ```
56
+ - `--title` — the essence of the problem, not an action: "Upload timeout ignores file size", not "Fix
57
+ the timeout".
58
+ - `--priority`: `critical` — breaks production or data; `high` — a bug the user will notice; `medium` —
59
+ debt that gets in the way of work; `low` — an improvement.
60
+ - `--tags` — the area of code and kind of work: `upload`, `auth`, `tech-debt`, `tests`.
61
+ - `--source` — where you noticed it, `file:line`.
62
+ - `--category` — required. For a code smell, use its category from the code-smells catalog: `bloaters`,
63
+ `change-preventers`, `couplers`, `data-dealers`, `dispensables`, `functional-abusers`,
64
+ `lexical-abusers`, `oo-abusers`, `obfuscators`. For incorrect behavior, use `bug`.
65
+ - `--found review` — a finding from an audit or review the user asked for; something noticed in passing
66
+ needs no flag.
67
+ - If you're working on a task from the backlog — add `--related <its ID>`.
68
+ - The checklist holds verifiable steps: progress is counted from it.
69
+ - Exit code 3 and "Looks like SPA-12 — …" mean such a task is already open: don't create a new one,
70
+ mention the existing ID in your answer. `--force` — only if it's definitely a different problem.
71
+ - Several small findings from one review (Minor level: smells, small inaccuracies) go into **one** task
72
+ rather than one each: title "Review nits: <what was reviewed>", one checklist item per finding
73
+ (`- [ ] Magic Number — src/a.ts:42: what's wrong`), `--category` — the most frequent category among
74
+ the findings, `--source` — the location of the first one. Separate tasks are only for important
75
+ findings and bugs.
76
+
77
+ 3. End your answer with a separate block that starts with the line "Added to backlog:" — that's how the
78
+ user finds new tasks in a long answer:
79
+ ```
80
+ Added to backlog:
81
+ - SPA-14 — Upload timeout ignores file size
82
+ ```
83
+ If the CLI printed "Created project …" — add that as one more line.
84
+
85
+ Several tasks about the same thing — gather them into an epic: create the epic (`backlog new --type epic
86
+ --title …`) and move the tasks with `backlog epic <ID> [<ID> …] --to <epic ID>`; `--to none` takes a task
87
+ out of its epic. An epic closes on its own once all its tasks are closed.
88
+
89
+ ## Take a task
90
+
91
+ "Take SPA-12" → `backlog take SPA-12`. "Take the next one" → `backlog take --next` (the project is picked
92
+ from the current repository; from another directory add `--project <id>`). "Take all tasks for
93
+ src/web/stats" → `backlog take --path src/web/stats`: takes every open task whose `source` is inside that
94
+ path (skipping blocked ones), and prints them one after another separated by `---` — fix them together,
95
+ closing each one.
96
+
97
+ | Code | What happened | What to do |
98
+ |---|---|---|
99
+ | 0 | Status became `in-progress`, the path, links, and task text were printed | Work on it |
100
+ | 1 | It's an epic | Show the user the epic's tasks from the output and ask which one to take |
101
+ | 2 | Task or project not found, no open tasks | Tell the user |
102
+ | 3 | Open blockers, or the task is already closed; with `--next` and `--path` — every matching task is blocked | List the blockers and stop. `--force` — only on the user's direct request |
103
+
104
+ 1. Read the description and `source`; for related tasks you need, use `backlog show <ID>`.
105
+ 2. Do the work. Finished a checklist item — mark it in the task file right away (`- [ ]` → `- [x]`, the
106
+ path is in the `take` output). New steps came up — add them to the checklist. Don't edit the
107
+ frontmatter by hand.
108
+ 3. Unrelated problems found along the way — through "Log a task" with `--related <ID>`.
109
+ 4. Before closing, verify the result with the project's own commands: tests, lint, types.
110
+ 5. Everything is done, verified, and committed → `backlog close <ID> --as fixed --reason "Fixed in <sha>:
111
+ <what exactly>"` — the hash lets stats know who fixed it and with what. No commit yet (changes aren't
112
+ committed) → `backlog status <ID> done`. If the CLI warned about unchecked items — check off the ones
113
+ that are done; if something isn't done, the task isn't finished.
114
+ 6. Not everything is done → leave the status `in-progress`, append a section to the end of the task file
115
+ and tell the user what's left:
116
+ ```markdown
117
+ ## Notes
118
+ - <today's date>: done …; left …, because …
119
+ ```
120
+
121
+ ## Re-check tasks
122
+
123
+ When: the hook message "code changed for tasks since the last check", a request to "check the backlog", or
124
+ "clean up the backlog".
125
+
126
+ 1. `backlog check --json` from the project's repository (from another directory — `--project <id>`).
127
+ Dangling references, completed epics, and shifted `source` — it already fixed those itself; that's the
128
+ `fixed` field, a list of `{ kind, taskId, … }`: `references-removed` — references to missing tasks `ids`
129
+ removed; `epic-closed` — the epic closed, all its tasks `childIds` are closed; `source-moved` — `source`
130
+ moved `from` → `to`. Relay it to the user in one line.
131
+ 2. A `source-changed` candidate already has `problem` in the JSON — the task description's first
132
+ paragraph — `snippet` — the current code around `source` with line numbers — and `diff` — the file's
133
+ changes since the last check (when cut short, `diffOmittedLines` says how many lines are not shown).
134
+ That's usually enough: decide from them without calling `show`, `grep`, or `git show`. Read the task (`backlog show <ID>`) and the whole file only when `snippet` and `diff`
135
+ aren't enough to tell; for `duplicate` and `no-source` always read the task.
136
+ 3. Decide:
137
+
138
+ | What the code shows | Command |
139
+ |---|---|
140
+ | The described problem is gone | `backlog close <ID> --as fixed --reason "Fixed in <sha>: <what exactly>"` (the CLI won't close it without an existing commit's hash) |
141
+ | The code or feature the task is about is gone | `backlog close <ID> --as obsolete --reason "<what was removed and where>"` |
142
+ | `source-missing`: the code moved (hint — `renamedTo`), the problem is still there | `backlog verify <ID> --source <new file:line>` |
143
+ | `source-missing`: the code the task is about is gone | `backlog close <ID> --as obsolete --reason "<what was removed and where>"` |
144
+ | `duplicate`: two tasks about the same thing | close the less complete one: `backlog close <ID> --as duplicate --duplicate-of <other> --reason "<what matches>"` |
145
+ | `duplicate`: tasks about different things | confirm both: `backlog verify <ID>` and `backlog verify <other>` |
146
+ | The problem is still there, but the code moved | `backlog verify <ID> --source <file:line>` |
147
+ | The problem is still there, or you're not sure | `backlog verify <ID>`; several at once — `backlog verify <ID> <ID> …` |
148
+
149
+ A plain `backlog verify <ID>` doesn't clear `source-missing`: a missing file leaves the candidates only
150
+ with a new `--source` or by closing the task, otherwise the hook will keep reminding about it after
151
+ every answer. Couldn't find where the code went — ask the user. A `duplicate` pair clears only once
152
+ both tasks are confirmed.
153
+
154
+ Only close with concrete evidence: a commit, a line, the fact the code is gone. "Looks outdated" is not
155
+ evidence: confirm the task and leave it open. A closed task is deleted along with its file after 7
156
+ days.
157
+
158
+ 4. `problems` — a list of `{ kind, … }`. `file-not-parsed`: the file `path` doesn't parse, reasons in
159
+ `problems` — fix the YAML by hand without changing `id`. List the rest for the user: `task-invalid` (error
160
+ `problem` in task `taskId`), `fix-failed` (the fix wasn't written, reason `cause`), `epics-wait-for-files`,
161
+ `project-without-repos`, `project-repos-missing`.
162
+ 5. End your answer with a block the user can use to find what was closed:
163
+ ```
164
+ Closed in the backlog:
165
+ - SPA-14 — Upload timeout ignores file size: fixed in a1b2c3d
166
+ ```
167
+ Don't list confirmed tasks individually — "The rest of the tasks were confirmed" is enough.
168
+
169
+ If the hook asked for the re-check, just end your answer afterward: the hook doesn't fire twice in a row.
170
+
171
+ ## Clean up stale minor tasks
172
+
173
+ When: the alert "Tasks with low priority older than 30 days", or a request to "clean up old tasks".
174
+
175
+ 1. `backlog prune` — lists tasks with low priority older than 30 days that were never taken up. Changes
176
+ nothing.
177
+ 2. Show the list to the user and ask whether to cancel them. They can raise the priority of tasks they
178
+ still need, or take them into progress.
179
+ 3. Only after explicit agreement — `backlog prune --apply`: cancels them as `obsolete`.
180
+
181
+ ## View the backlog
182
+
183
+ A project that's no longer maintained is marked inactive: `backlog project status <id> inactive` — its
184
+ tasks drop out of the combined "Projects" scope (list and stats) but stay available on the project's own
185
+ page. `backlog project list` shows the statuses. Deleting a project (`backlog project delete <id> --confirm
186
+ <id>`) removes the directory with all its tasks — do this only on the user's direct request.
187
+
188
+ "What's in the backlog" → `backlog list`: the current project's open tasks by priority. On request:
189
+ `--all-projects`, `--status done`, `--tag <tag>`, `--query <text>`. For details — `backlog show <ID>`.
190
+
191
+ Summary and alerts — `backlog stats`.
192
+
193
+ To change the category — `backlog category <ID> <category|none>`. To change the priority —
194
+ `backlog priority <ID> <low|medium|high|critical>`.