issue-flow 0.18.0 → 0.20.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.
- package/README.md +43 -97
- package/dist/agent-4DHRKZ2Z.js +32 -0
- package/dist/{analyze-Q4ONIWRZ.js → analyze-UEJ2R3H5.js} +42 -41
- package/dist/analyze-UEJ2R3H5.js.map +1 -0
- package/dist/{apply-EEFPY2W4.js → apply-QDYNQMUX.js} +22 -24
- package/dist/apply-QDYNQMUX.js.map +1 -0
- package/dist/artifacts-AMJQJFFV.js +82 -0
- package/dist/artifacts-AMJQJFFV.js.map +1 -0
- package/dist/{bench-WWWXLTFH.js → bench-RNRXVEFK.js} +42 -42
- package/dist/{chunk-RYOUZ6EK.js → chunk-23VHVVKW.js} +3 -3
- package/dist/chunk-2EYLOS5I.js +99 -0
- package/dist/chunk-2EYLOS5I.js.map +1 -0
- package/dist/{chunk-C5TL7T4V.js → chunk-2YM2VH6R.js} +2 -2
- package/dist/{chunk-XUEMATVY.js → chunk-37O2FMAN.js} +28 -25
- package/dist/chunk-37O2FMAN.js.map +1 -0
- package/dist/chunk-44RF3VFG.js +717 -0
- package/dist/chunk-44RF3VFG.js.map +1 -0
- package/dist/chunk-6AOZCWN2.js +21 -0
- package/dist/chunk-6AOZCWN2.js.map +1 -0
- package/dist/chunk-7MJGYPHF.js +1571 -0
- package/dist/chunk-7MJGYPHF.js.map +1 -0
- package/dist/{chunk-SA6HXL4Y.js → chunk-7WBUEBD5.js} +9 -9
- package/dist/chunk-7WBUEBD5.js.map +1 -0
- package/dist/chunk-7ZZUSMBJ.js +35 -0
- package/dist/chunk-7ZZUSMBJ.js.map +1 -0
- package/dist/{chunk-QJ44VG5G.js → chunk-ADH6RJNX.js} +3 -3
- package/dist/{chunk-34OCSKOB.js → chunk-AKL5UPR6.js} +159 -114
- package/dist/chunk-AKL5UPR6.js.map +1 -0
- package/dist/{chunk-7F7LGMVO.js → chunk-BTBJ5UOO.js} +12 -12
- package/dist/{chunk-7F7LGMVO.js.map → chunk-BTBJ5UOO.js.map} +1 -1
- package/dist/{chunk-HOAHMERN.js → chunk-CLZ6RRZL.js} +21 -21
- package/dist/chunk-DBLXLKGU.js +1201 -0
- package/dist/chunk-DBLXLKGU.js.map +1 -0
- package/dist/{chunk-DUS5ZNKL.js → chunk-DIMDAYZS.js} +7 -6
- package/dist/chunk-DZ3DZ3EN.js +278 -0
- package/dist/chunk-DZ3DZ3EN.js.map +1 -0
- package/dist/{chunk-CRGIQFUQ.js → chunk-E2H3JV2E.js} +3 -1
- package/dist/chunk-E2H3JV2E.js.map +1 -0
- package/dist/{chunk-45WZ6GMI.js → chunk-EORDSKWZ.js} +17 -17
- package/dist/chunk-EORDSKWZ.js.map +1 -0
- package/dist/{chunk-LTH6XYZ3.js → chunk-EYKPWHT7.js} +40 -30
- package/dist/chunk-EYKPWHT7.js.map +1 -0
- package/dist/{chunk-OODXFCQV.js → chunk-FU2FQ4JE.js} +14 -16
- package/dist/{chunk-OODXFCQV.js.map → chunk-FU2FQ4JE.js.map} +1 -1
- package/dist/{chunk-V7QOIQYC.js → chunk-G442RDFX.js} +9 -23
- package/dist/{chunk-V7QOIQYC.js.map → chunk-G442RDFX.js.map} +1 -1
- package/dist/{chunk-QPGEFLMY.js → chunk-I64N6RL6.js} +7 -7
- package/dist/{chunk-KRAGAUKD.js → chunk-JBYXJOJJ.js} +201 -64
- package/dist/chunk-JBYXJOJJ.js.map +1 -0
- package/dist/{chunk-SOM4QA6C.js → chunk-JCR5C5A7.js} +93 -18
- package/dist/chunk-JCR5C5A7.js.map +1 -0
- package/dist/{chunk-RNFUVKC3.js → chunk-K5NM26NV.js} +30 -13
- package/dist/chunk-K5NM26NV.js.map +1 -0
- package/dist/{chunk-YVPZUN6X.js → chunk-KUA6KBBD.js} +335 -38
- package/dist/chunk-KUA6KBBD.js.map +1 -0
- package/dist/{chunk-KMCS76ZW.js → chunk-KUL64XUF.js} +44 -12
- package/dist/chunk-KUL64XUF.js.map +1 -0
- package/dist/{chunk-HAKDLR6N.js → chunk-MAJ6QDRL.js} +65 -78
- package/dist/chunk-MAJ6QDRL.js.map +1 -0
- package/dist/{chunk-DGRTJD5R.js → chunk-MML2G7IC.js} +7 -7
- package/dist/chunk-NP47HRX2.js +136 -0
- package/dist/chunk-NP47HRX2.js.map +1 -0
- package/dist/{chunk-3R27MJ5R.js → chunk-PFWHHYEO.js} +3 -3
- package/dist/{chunk-ECU7YO7S.js → chunk-PM5YWJYO.js} +22 -6
- package/dist/chunk-PM5YWJYO.js.map +1 -0
- package/dist/{chunk-E4I6MMHD.js → chunk-PXPTIXJF.js} +154 -101
- package/dist/chunk-PXPTIXJF.js.map +1 -0
- package/dist/{chunk-CWSQVHVV.js → chunk-QJHZ3HYJ.js} +248 -102
- package/dist/chunk-QJHZ3HYJ.js.map +1 -0
- package/dist/{chunk-LI35PIIS.js → chunk-RDPK7LYK.js} +20 -117
- package/dist/chunk-RDPK7LYK.js.map +1 -0
- package/dist/{chunk-PMLE7KAQ.js → chunk-RMIBLFG3.js} +30 -14
- package/dist/chunk-RMIBLFG3.js.map +1 -0
- package/dist/{chunk-62GVVZQO.js → chunk-T736DSZI.js} +32 -316
- package/dist/chunk-T736DSZI.js.map +1 -0
- package/dist/{chunk-TZYINKCC.js → chunk-UDUUUFQF.js} +57 -29
- package/dist/chunk-UDUUUFQF.js.map +1 -0
- package/dist/{chunk-NEWNXZ65.js → chunk-V7GETODQ.js} +36 -28
- package/dist/{chunk-NEWNXZ65.js.map → chunk-V7GETODQ.js.map} +1 -1
- package/dist/{chunk-PPZ3K4YM.js → chunk-VHQMMY2D.js} +2 -2
- package/dist/{chunk-ZVZMWNCG.js → chunk-VJ3PF6B7.js} +50 -16
- package/dist/chunk-VJ3PF6B7.js.map +1 -0
- package/dist/{chunk-L6HSKTQE.js → chunk-W7LZLJAF.js} +4 -4
- package/dist/{chunk-6K2LCFG6.js → chunk-WB4FA2EH.js} +70 -81
- package/dist/chunk-WB4FA2EH.js.map +1 -0
- package/dist/{chunk-LGHND47K.js → chunk-WQSGL5LX.js} +22 -16
- package/dist/chunk-WQSGL5LX.js.map +1 -0
- package/dist/{chunk-ICM463EO.js → chunk-XNK5UN2D.js} +5 -649
- package/dist/chunk-XNK5UN2D.js.map +1 -0
- package/dist/{chunk-7UMMFOL2.js → chunk-Y2KOWABB.js} +39 -24
- package/dist/chunk-Y2KOWABB.js.map +1 -0
- package/dist/{chunk-QF7VEL3M.js → chunk-YC24E66P.js} +568 -158
- package/dist/chunk-YC24E66P.js.map +1 -0
- package/dist/{chunk-EG2MGDP5.js → chunk-Z6RCKCVB.js} +52 -46
- package/dist/chunk-Z6RCKCVB.js.map +1 -0
- package/dist/{chunk-YUNBOUQH.js → chunk-ZPGNVBWY.js} +8 -8
- package/dist/cli.js +132 -62
- package/dist/cli.js.map +1 -1
- package/dist/compat-OJG76J4I.js +24 -0
- package/dist/{config-LEBZZCJP.js → config-6YTWPDBK.js} +20 -17
- package/dist/{contract-JH2WBIO6.js → contract-HWLFFL3F.js} +2 -2
- package/dist/{conventions-XOT6YW5L.js → conventions-5UPOTU42.js} +20 -16
- package/dist/{conventions-XOT6YW5L.js.map → conventions-5UPOTU42.js.map} +1 -1
- package/dist/db-QAZG4LQD.js +264 -0
- package/dist/db-QAZG4LQD.js.map +1 -0
- package/dist/diagnostics-YEFB42E5.js +25 -0
- package/dist/execute-QCT64D37.js +38 -0
- package/dist/{generate-JGW5JSKB.js → generate-QATMDKOK.js} +46 -43
- package/dist/generate-QATMDKOK.js.map +1 -0
- package/dist/{git-A2IP32PQ.js → git-XGOECXWG.js} +2 -3
- package/dist/history-NBPUZVGQ.js +101 -0
- package/dist/history-NBPUZVGQ.js.map +1 -0
- package/dist/init-4LB2YKWP.js +28 -0
- package/dist/{operations-O4FORFIH.js → operations-RUQP2Y2F.js} +78 -52
- package/dist/operations-RUQP2Y2F.js.map +1 -0
- package/dist/{permissions-G4XCAESF.js → permissions-QZPUUBSO.js} +5 -6
- package/dist/plan-2NMSHTMD.js +38 -0
- package/dist/{policy-U5NBFAO5.js → policy-RKKFF5A2.js} +17 -15
- package/dist/{policy-U5NBFAO5.js.map → policy-RKKFF5A2.js.map} +1 -1
- package/dist/pr-QKFO5HI3.js +42 -0
- package/dist/pr-review-H2BFD6F2.js +33 -0
- package/dist/prd-ET6XKYRS.js +37 -0
- package/dist/{ps-76L6ZAZL.js → ps-UIKSOUAQ.js} +26 -15
- package/dist/ps-UIKSOUAQ.js.map +1 -0
- package/dist/{recorder-2BAKPBRA.js → recorder-LOU3PTIE.js} +11 -7
- package/dist/registry-HV7M6MAH.js +17 -0
- package/dist/repository-RCRR6RDE.js +80 -0
- package/dist/resume-BWJZGBLZ.js +278 -0
- package/dist/resume-BWJZGBLZ.js.map +1 -0
- package/dist/review-2MTZLNSS.js +38 -0
- package/dist/routing-RM5ABHHD.js +35 -0
- package/dist/run-XMACQBRJ.js +61 -0
- package/dist/{session-publisher-KAJQRHNZ.js → session-publisher-Q5TNEZPX.js} +3 -3
- package/dist/session-publisher-Q5TNEZPX.js.map +1 -0
- package/dist/{state-manager-UPHO2EA2.js → state-manager-SRN4VJSX.js} +9 -4
- package/dist/state-manager-SRN4VJSX.js.map +1 -0
- package/dist/{usage-KTMYXAPF.js → usage-JOODVE5O.js} +69 -63
- package/dist/usage-JOODVE5O.js.map +1 -0
- package/dist/web-TLMWJ2BM.js +205 -0
- package/dist/web-TLMWJ2BM.js.map +1 -0
- package/package.json +22 -8
- package/prompts/analyze.md +16 -19
- package/prompts/execute.md +73 -144
- package/prompts/generate.md +23 -10
- package/prompts/plan.md +32 -60
- package/prompts/pr-review.md +58 -40
- package/prompts/pr.md +50 -16
- package/prompts/prd.md +26 -19
- package/prompts/review.md +41 -18
- package/web/public/app.js +111 -112
- package/dist/agent-HMZTXCRT.js +0 -30
- package/dist/analyze-Q4ONIWRZ.js.map +0 -1
- package/dist/apply-EEFPY2W4.js.map +0 -1
- package/dist/chunk-34OCSKOB.js.map +0 -1
- package/dist/chunk-45WZ6GMI.js.map +0 -1
- package/dist/chunk-62GVVZQO.js.map +0 -1
- package/dist/chunk-6K2LCFG6.js.map +0 -1
- package/dist/chunk-7UMMFOL2.js.map +0 -1
- package/dist/chunk-CRGIQFUQ.js.map +0 -1
- package/dist/chunk-CWSQVHVV.js.map +0 -1
- package/dist/chunk-E4I6MMHD.js.map +0 -1
- package/dist/chunk-ECU7YO7S.js.map +0 -1
- package/dist/chunk-EG2MGDP5.js.map +0 -1
- package/dist/chunk-HAKDLR6N.js.map +0 -1
- package/dist/chunk-ICM463EO.js.map +0 -1
- package/dist/chunk-KMCS76ZW.js.map +0 -1
- package/dist/chunk-KRAGAUKD.js.map +0 -1
- package/dist/chunk-LGHND47K.js.map +0 -1
- package/dist/chunk-LI35PIIS.js.map +0 -1
- package/dist/chunk-LTH6XYZ3.js.map +0 -1
- package/dist/chunk-PMLE7KAQ.js.map +0 -1
- package/dist/chunk-QF7VEL3M.js.map +0 -1
- package/dist/chunk-RNFUVKC3.js.map +0 -1
- package/dist/chunk-SA6HXL4Y.js.map +0 -1
- package/dist/chunk-SOM4QA6C.js.map +0 -1
- package/dist/chunk-TZYINKCC.js.map +0 -1
- package/dist/chunk-WCCZJL7W.js +0 -141
- package/dist/chunk-WCCZJL7W.js.map +0 -1
- package/dist/chunk-XEYH6ZZI.js +0 -289
- package/dist/chunk-XEYH6ZZI.js.map +0 -1
- package/dist/chunk-XUEMATVY.js.map +0 -1
- package/dist/chunk-XZUEFTUP.js +0 -243
- package/dist/chunk-XZUEFTUP.js.map +0 -1
- package/dist/chunk-YVPZUN6X.js.map +0 -1
- package/dist/chunk-ZVZMWNCG.js.map +0 -1
- package/dist/diagnostics-HTCWF7F4.js +0 -23
- package/dist/execute-LELOSR5T.js +0 -37
- package/dist/generate-JGW5JSKB.js.map +0 -1
- package/dist/init-TO6MUXO4.js +0 -26
- package/dist/operations-O4FORFIH.js.map +0 -1
- package/dist/plan-OXAT344Q.js +0 -34
- package/dist/pr-UZHNKKZC.js +0 -39
- package/dist/pr-review-Q4ACAWDM.js +0 -32
- package/dist/prd-6CYEMLDY.js +0 -33
- package/dist/ps-76L6ZAZL.js.map +0 -1
- package/dist/registry-XLHHYLTR.js +0 -15
- package/dist/resume-URCU6CIJ.js +0 -244
- package/dist/resume-URCU6CIJ.js.map +0 -1
- package/dist/review-LVZT2TMW.js +0 -35
- package/dist/routing-EK6RBZM4.js +0 -33
- package/dist/run-2RXJCJKT.js +0 -56
- package/dist/usage-KTMYXAPF.js.map +0 -1
- package/dist/web-B5UPHHR5.js +0 -172
- package/dist/web-B5UPHHR5.js.map +0 -1
- /package/dist/{agent-HMZTXCRT.js.map → agent-4DHRKZ2Z.js.map} +0 -0
- /package/dist/{bench-WWWXLTFH.js.map → bench-RNRXVEFK.js.map} +0 -0
- /package/dist/{chunk-RYOUZ6EK.js.map → chunk-23VHVVKW.js.map} +0 -0
- /package/dist/{chunk-C5TL7T4V.js.map → chunk-2YM2VH6R.js.map} +0 -0
- /package/dist/{chunk-QJ44VG5G.js.map → chunk-ADH6RJNX.js.map} +0 -0
- /package/dist/{chunk-HOAHMERN.js.map → chunk-CLZ6RRZL.js.map} +0 -0
- /package/dist/{chunk-DUS5ZNKL.js.map → chunk-DIMDAYZS.js.map} +0 -0
- /package/dist/{chunk-QPGEFLMY.js.map → chunk-I64N6RL6.js.map} +0 -0
- /package/dist/{chunk-DGRTJD5R.js.map → chunk-MML2G7IC.js.map} +0 -0
- /package/dist/{chunk-3R27MJ5R.js.map → chunk-PFWHHYEO.js.map} +0 -0
- /package/dist/{chunk-PPZ3K4YM.js.map → chunk-VHQMMY2D.js.map} +0 -0
- /package/dist/{chunk-L6HSKTQE.js.map → chunk-W7LZLJAF.js.map} +0 -0
- /package/dist/{chunk-YUNBOUQH.js.map → chunk-ZPGNVBWY.js.map} +0 -0
- /package/dist/{config-LEBZZCJP.js.map → compat-OJG76J4I.js.map} +0 -0
- /package/dist/{contract-JH2WBIO6.js.map → config-6YTWPDBK.js.map} +0 -0
- /package/dist/{diagnostics-HTCWF7F4.js.map → contract-HWLFFL3F.js.map} +0 -0
- /package/dist/{execute-LELOSR5T.js.map → diagnostics-YEFB42E5.js.map} +0 -0
- /package/dist/{git-A2IP32PQ.js.map → execute-QCT64D37.js.map} +0 -0
- /package/dist/{init-TO6MUXO4.js.map → git-XGOECXWG.js.map} +0 -0
- /package/dist/{permissions-G4XCAESF.js.map → init-4LB2YKWP.js.map} +0 -0
- /package/dist/{plan-OXAT344Q.js.map → permissions-QZPUUBSO.js.map} +0 -0
- /package/dist/{pr-UZHNKKZC.js.map → plan-2NMSHTMD.js.map} +0 -0
- /package/dist/{pr-review-Q4ACAWDM.js.map → pr-QKFO5HI3.js.map} +0 -0
- /package/dist/{prd-6CYEMLDY.js.map → pr-review-H2BFD6F2.js.map} +0 -0
- /package/dist/{recorder-2BAKPBRA.js.map → prd-ET6XKYRS.js.map} +0 -0
- /package/dist/{registry-XLHHYLTR.js.map → recorder-LOU3PTIE.js.map} +0 -0
- /package/dist/{review-LVZT2TMW.js.map → registry-HV7M6MAH.js.map} +0 -0
- /package/dist/{routing-EK6RBZM4.js.map → repository-RCRR6RDE.js.map} +0 -0
- /package/dist/{run-2RXJCJKT.js.map → review-2MTZLNSS.js.map} +0 -0
- /package/dist/{session-publisher-KAJQRHNZ.js.map → routing-RM5ABHHD.js.map} +0 -0
- /package/dist/{state-manager-UPHO2EA2.js.map → run-XMACQBRJ.js.map} +0 -0
package/web/public/app.js
CHANGED
|
@@ -177,7 +177,7 @@
|
|
|
177
177
|
|
|
178
178
|
// Ícone textual (○ ● ✓ ✗): a cor e o rótulo ao lado já dizem o estado.
|
|
179
179
|
function statusIcon(status, symbol) {
|
|
180
|
-
const icon = el('span',
|
|
180
|
+
const icon = el('span', `item-icon icon-${status}`, symbol || PHASE_ICONS[status] || '○');
|
|
181
181
|
icon.setAttribute('aria-hidden', 'true');
|
|
182
182
|
return icon;
|
|
183
183
|
}
|
|
@@ -203,17 +203,17 @@
|
|
|
203
203
|
function formatDuration(totalSeconds) {
|
|
204
204
|
if (totalSeconds === null || totalSeconds === undefined || totalSeconds < 0) return '—';
|
|
205
205
|
const seconds = Math.round(totalSeconds);
|
|
206
|
-
if (seconds < 60) return seconds
|
|
206
|
+
if (seconds < 60) return `${seconds}s`;
|
|
207
207
|
const minutes = Math.floor(seconds / 60);
|
|
208
|
-
if (minutes < 60) return minutes
|
|
208
|
+
if (minutes < 60) return `${minutes}min ${String(seconds % 60).padStart(2, '0')}s`;
|
|
209
209
|
const hours = Math.floor(minutes / 60);
|
|
210
|
-
return hours
|
|
210
|
+
return `${hours}h ${String(minutes % 60).padStart(2, '0')}min`;
|
|
211
211
|
}
|
|
212
212
|
|
|
213
213
|
function formatAgo(iso) {
|
|
214
214
|
const ms = parseIso(iso);
|
|
215
215
|
if (ms === null) return '';
|
|
216
|
-
return
|
|
216
|
+
return `há ${formatDuration((Date.now() - ms) / 1000)}`;
|
|
217
217
|
}
|
|
218
218
|
|
|
219
219
|
function formatClock(iso) {
|
|
@@ -233,8 +233,8 @@
|
|
|
233
233
|
// 1523 → 1.5k, 2400000 → 2.4M (mesma regra do resumo no terminal).
|
|
234
234
|
function compactTokens(value) {
|
|
235
235
|
const abs = Math.abs(value);
|
|
236
|
-
if (abs >= 1000000) return (value / 1000000).toFixed(1)
|
|
237
|
-
if (abs >= 1000) return (value / 1000).toFixed(1)
|
|
236
|
+
if (abs >= 1000000) return `${(value / 1000000).toFixed(1)}M`;
|
|
237
|
+
if (abs >= 1000) return `${(value / 1000).toFixed(1)}k`;
|
|
238
238
|
return String(Math.round(value));
|
|
239
239
|
}
|
|
240
240
|
|
|
@@ -253,14 +253,14 @@
|
|
|
253
253
|
const input = metric(usage.inputTokens);
|
|
254
254
|
const output = metric(usage.outputTokens);
|
|
255
255
|
const io = [];
|
|
256
|
-
if (input !== null) io.push(compactTokens(input)
|
|
257
|
-
if (output !== null) io.push(compactTokens(output)
|
|
256
|
+
if (input !== null) io.push(`${compactTokens(input)} in`);
|
|
257
|
+
if (output !== null) io.push(`${compactTokens(output)} out`);
|
|
258
258
|
if (io.length > 0) segments.push(io.join(' / '));
|
|
259
259
|
|
|
260
260
|
const cacheRead = metric(usage.cacheReadTokens);
|
|
261
261
|
const cacheCreation = metric(usage.cacheCreationTokens);
|
|
262
262
|
if (cacheRead !== null || cacheCreation !== null) {
|
|
263
|
-
segments.push(compactTokens((cacheRead || 0) + (cacheCreation || 0))
|
|
263
|
+
segments.push(`${compactTokens((cacheRead || 0) + (cacheCreation || 0))} cache`);
|
|
264
264
|
}
|
|
265
265
|
|
|
266
266
|
const cost = metric(usage.costUsd);
|
|
@@ -289,7 +289,7 @@
|
|
|
289
289
|
|
|
290
290
|
// URL do repositório derivada da URL da issue (…/issues/N → raiz do repo).
|
|
291
291
|
function repoUrl(snapshot) {
|
|
292
|
-
const url = snapshot.issue
|
|
292
|
+
const url = snapshot.issue?.url;
|
|
293
293
|
if (!url) return null;
|
|
294
294
|
const match = url.match(/^(https?:\/\/\S+?)\/issues\/\d+\/?$/);
|
|
295
295
|
return match ? match[1] : null;
|
|
@@ -357,7 +357,7 @@
|
|
|
357
357
|
if (panel) panel.hidden = !active;
|
|
358
358
|
if (active) focused = tab;
|
|
359
359
|
}
|
|
360
|
-
if (options
|
|
360
|
+
if (options?.focus && focused) focused.focus();
|
|
361
361
|
}
|
|
362
362
|
|
|
363
363
|
// Padrão ARIA de tablist: setas movem entre as abas, Home/End vão às pontas.
|
|
@@ -386,7 +386,7 @@
|
|
|
386
386
|
let raw = null;
|
|
387
387
|
try {
|
|
388
388
|
raw = window.localStorage.getItem(THEME_STORAGE_KEY);
|
|
389
|
-
} catch (
|
|
389
|
+
} catch (_err) {
|
|
390
390
|
// localStorage indisponível (ex.: bloqueado) — segue no modo sistema.
|
|
391
391
|
}
|
|
392
392
|
return raw === 'light' || raw === 'dark' ? raw : 'system';
|
|
@@ -395,7 +395,7 @@
|
|
|
395
395
|
function storeTheme(value) {
|
|
396
396
|
try {
|
|
397
397
|
window.localStorage.setItem(THEME_STORAGE_KEY, value);
|
|
398
|
-
} catch (
|
|
398
|
+
} catch (_err) {
|
|
399
399
|
// Persistência é conveniência; falha é ignorada. Sem gravar, a escolha
|
|
400
400
|
// continua valendo nesta aba — só não sobrevive ao reload.
|
|
401
401
|
}
|
|
@@ -463,7 +463,7 @@
|
|
|
463
463
|
let raw = null;
|
|
464
464
|
try {
|
|
465
465
|
raw = window.localStorage.getItem(STORAGE_KEY);
|
|
466
|
-
} catch (
|
|
466
|
+
} catch (_err) {
|
|
467
467
|
// localStorage indisponível (ex.: bloqueado) — segue com o default.
|
|
468
468
|
}
|
|
469
469
|
if (raw === null) return null;
|
|
@@ -474,7 +474,7 @@
|
|
|
474
474
|
function storeRefresh(value) {
|
|
475
475
|
try {
|
|
476
476
|
window.localStorage.setItem(STORAGE_KEY, String(value));
|
|
477
|
-
} catch (
|
|
477
|
+
} catch (_err) {
|
|
478
478
|
// Persistência é conveniência; falha é ignorada.
|
|
479
479
|
}
|
|
480
480
|
}
|
|
@@ -488,7 +488,7 @@
|
|
|
488
488
|
}
|
|
489
489
|
clear(select);
|
|
490
490
|
for (const value of values) {
|
|
491
|
-
const option = el('option', null, value
|
|
491
|
+
const option = el('option', null, `${value}s`);
|
|
492
492
|
option.value = String(value);
|
|
493
493
|
select.appendChild(option);
|
|
494
494
|
}
|
|
@@ -561,14 +561,14 @@
|
|
|
561
561
|
}
|
|
562
562
|
|
|
563
563
|
function statusUrlFor(session) {
|
|
564
|
-
if (!session
|
|
564
|
+
if (!session?.statusUrl) return 'api/status';
|
|
565
565
|
// statusUrl vem com barra inicial (/api/status?session=…); o fetch relativo
|
|
566
566
|
// ao path do painel precisa da forma sem a barra absoluta do host.
|
|
567
567
|
return session.statusUrl.replace(/^\//, '');
|
|
568
568
|
}
|
|
569
569
|
|
|
570
570
|
function eventsUrlFor(session) {
|
|
571
|
-
if (!session
|
|
571
|
+
if (!session?.eventsUrl) return null;
|
|
572
572
|
return session.eventsUrl.replace(/^\//, '');
|
|
573
573
|
}
|
|
574
574
|
|
|
@@ -586,7 +586,7 @@
|
|
|
586
586
|
// então é ela que explica o que está na tela. As duas aparecem juntas no card
|
|
587
587
|
// de configuração quando divergem.
|
|
588
588
|
function renderMonitorVersion(version) {
|
|
589
|
-
const label = typeof version === 'string' && version !== '' ?
|
|
589
|
+
const label = typeof version === 'string' && version !== '' ? `v${version}` : null;
|
|
590
590
|
state.monitorVersion = label === null ? null : version;
|
|
591
591
|
for (const node of [els.appVersion, els.appVersionDashboard]) {
|
|
592
592
|
if (!node) continue;
|
|
@@ -643,7 +643,7 @@
|
|
|
643
643
|
try {
|
|
644
644
|
const sessionsRes = await fetch('api/sessions', { cache: 'no-store' });
|
|
645
645
|
if (serverInstanceChanged(sessionsRes)) return;
|
|
646
|
-
if (!sessionsRes.ok) throw new Error(
|
|
646
|
+
if (!sessionsRes.ok) throw new Error(`HTTP ${sessionsRes.status}`);
|
|
647
647
|
const sessions = await sessionsRes.json();
|
|
648
648
|
if (!Array.isArray(sessions)) throw new Error('sessions payload invalid');
|
|
649
649
|
|
|
@@ -701,12 +701,12 @@
|
|
|
701
701
|
return;
|
|
702
702
|
}
|
|
703
703
|
if (res.status !== 304) {
|
|
704
|
-
if (!res.ok) throw new Error(
|
|
704
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
705
705
|
state.etag = res.headers.get('ETag');
|
|
706
706
|
state.snapshot = await res.json();
|
|
707
707
|
render();
|
|
708
708
|
}
|
|
709
|
-
const configUrl =
|
|
709
|
+
const configUrl = `api/config?session=${encodeURIComponent(state.detailSessionId || '')}`;
|
|
710
710
|
const configRes = await fetch(configUrl, { cache: 'no-store' });
|
|
711
711
|
if (configRes.ok) {
|
|
712
712
|
state.configData = await configRes.json();
|
|
@@ -714,11 +714,10 @@
|
|
|
714
714
|
}
|
|
715
715
|
if (state.eventsUrl) {
|
|
716
716
|
const eventsRes = await fetch(state.eventsUrl, { cache: 'no-store' });
|
|
717
|
-
if (!eventsRes.ok) throw new Error(
|
|
717
|
+
if (!eventsRes.ok) throw new Error(`HTTP ${eventsRes.status}`);
|
|
718
718
|
const entries = await eventsRes.json();
|
|
719
719
|
state.events = Array.isArray(entries) ? entries : [];
|
|
720
|
-
const diagnosticUrl =
|
|
721
|
-
'api/diagnostics?session=' + encodeURIComponent(state.detailSessionId || '');
|
|
720
|
+
const diagnosticUrl = `api/diagnostics?session=${encodeURIComponent(state.detailSessionId || '')}`;
|
|
722
721
|
const diagnosticsRes = await fetch(diagnosticUrl, { cache: 'no-store' });
|
|
723
722
|
if (diagnosticsRes.ok) {
|
|
724
723
|
const diagnostics = await diagnosticsRes.json();
|
|
@@ -730,7 +729,7 @@
|
|
|
730
729
|
setViewMode('detail');
|
|
731
730
|
state.failures = 0;
|
|
732
731
|
els.banner.hidden = true;
|
|
733
|
-
} catch (
|
|
732
|
+
} catch (_err) {
|
|
734
733
|
state.failures += 1;
|
|
735
734
|
els.banner.hidden = false;
|
|
736
735
|
} finally {
|
|
@@ -761,7 +760,7 @@
|
|
|
761
760
|
if (!text) return '';
|
|
762
761
|
const normalized = String(text).replace(/\s+/g, ' ').trim();
|
|
763
762
|
if (normalized.length <= max) return normalized;
|
|
764
|
-
return normalized.slice(0, max - 1).trimEnd()
|
|
763
|
+
return `${normalized.slice(0, max - 1).trimEnd()}…`;
|
|
765
764
|
}
|
|
766
765
|
|
|
767
766
|
// Linha secundária do header do dashboard: quantas execuções e em que
|
|
@@ -777,16 +776,16 @@
|
|
|
777
776
|
const count = counts[status];
|
|
778
777
|
if (!count) continue;
|
|
779
778
|
const label = SUMMARY_STATUS_LABELS[status];
|
|
780
|
-
parts.push(count
|
|
779
|
+
parts.push(`${count} ${count === 1 ? label[0] : label[1]}`);
|
|
781
780
|
}
|
|
782
781
|
const total = sessions.length + (sessions.length === 1 ? ' execução' : ' execuções');
|
|
783
|
-
els.dashboardSummary.textContent = parts.length > 0 ? total
|
|
782
|
+
els.dashboardSummary.textContent = parts.length > 0 ? `${total} · ${parts.join(' · ')}` : total;
|
|
784
783
|
}
|
|
785
784
|
|
|
786
785
|
function renderDashboard(sessions) {
|
|
787
786
|
const active = document.activeElement;
|
|
788
787
|
const focusedId =
|
|
789
|
-
active
|
|
788
|
+
active?.dataset && els.dashboard.contains(active) && active.dataset.sessionId
|
|
790
789
|
? active.dataset.sessionId
|
|
791
790
|
: null;
|
|
792
791
|
|
|
@@ -815,7 +814,7 @@
|
|
|
815
814
|
'dashboard-project',
|
|
816
815
|
session.repositoryName || 'Projeto desconhecido',
|
|
817
816
|
);
|
|
818
|
-
const badge = el('span',
|
|
817
|
+
const badge = el('span', `badge status-${session.status || 'idle'}`);
|
|
819
818
|
badge.textContent = STATUS_LABELS[session.status] || session.status || '—';
|
|
820
819
|
head.appendChild(project);
|
|
821
820
|
head.appendChild(badge);
|
|
@@ -823,7 +822,7 @@
|
|
|
823
822
|
|
|
824
823
|
const titleRow = el('span', 'dashboard-title-row');
|
|
825
824
|
if (session.issueNumber !== null && session.issueNumber !== undefined) {
|
|
826
|
-
titleRow.appendChild(el('span', 'dashboard-issue',
|
|
825
|
+
titleRow.appendChild(el('span', 'dashboard-issue', `#${session.issueNumber}`));
|
|
827
826
|
}
|
|
828
827
|
titleRow.appendChild(el('span', 'dashboard-title', session.issueTitle || 'Sem título'));
|
|
829
828
|
card.appendChild(titleRow);
|
|
@@ -832,9 +831,9 @@
|
|
|
832
831
|
card.appendChild(el('span', 'dashboard-summary muted', summary || 'Sem descrição'));
|
|
833
832
|
|
|
834
833
|
const meta = el('span', 'dashboard-meta-row');
|
|
835
|
-
meta.appendChild(el('span', null,
|
|
834
|
+
meta.appendChild(el('span', null, `Fase: ${session.currentPhase || '—'}`));
|
|
836
835
|
const percent = typeof session.progressPercent === 'number' ? session.progressPercent : 0;
|
|
837
|
-
meta.appendChild(el('span', null, percent
|
|
836
|
+
meta.appendChild(el('span', null, `${percent}%`));
|
|
838
837
|
const elapsed =
|
|
839
838
|
typeof session.elapsedSeconds === 'number'
|
|
840
839
|
? formatDuration(session.elapsedSeconds)
|
|
@@ -846,25 +845,25 @@
|
|
|
846
845
|
// A card that only shows a percentage cannot tell a run that is
|
|
847
846
|
// progressing from one that has been retrying for twenty minutes.
|
|
848
847
|
if (typeof session.retries === 'number' && session.retries > 0) {
|
|
849
|
-
meta.appendChild(el('span', null, session.retries
|
|
848
|
+
meta.appendChild(el('span', null, `${session.retries} retry(s)`));
|
|
850
849
|
}
|
|
851
850
|
if (typeof session.correctionCycle === 'number' && session.correctionCycle > 0) {
|
|
852
|
-
meta.appendChild(el('span', null,
|
|
851
|
+
meta.appendChild(el('span', null, `correção ${session.correctionCycle}`));
|
|
853
852
|
}
|
|
854
853
|
if (session.updatedAt) {
|
|
855
854
|
meta.appendChild(
|
|
856
|
-
el('span', null,
|
|
855
|
+
el('span', null, `atividade ${formatAgo(session.lastActivityAt || session.updatedAt)}`),
|
|
857
856
|
);
|
|
858
857
|
}
|
|
859
|
-
if (session.provider) meta.appendChild(el('span', null,
|
|
858
|
+
if (session.provider) meta.appendChild(el('span', null, `provider ${session.provider}`));
|
|
860
859
|
if (typeof session.attempt === 'number' && session.attempt > 0) {
|
|
861
|
-
meta.appendChild(el('span', null,
|
|
860
|
+
meta.appendChild(el('span', null, `tentativa ${session.attempt}`));
|
|
862
861
|
}
|
|
863
862
|
card.appendChild(meta);
|
|
864
863
|
|
|
865
864
|
const progress = el('span', 'dashboard-progress');
|
|
866
865
|
const bar = el('span', 'dashboard-progress-bar');
|
|
867
|
-
bar.style.width = Math.max(0, Math.min(100, percent))
|
|
866
|
+
bar.style.width = `${Math.max(0, Math.min(100, percent))}%`;
|
|
868
867
|
progress.appendChild(bar);
|
|
869
868
|
card.appendChild(progress);
|
|
870
869
|
|
|
@@ -884,11 +883,11 @@
|
|
|
884
883
|
|
|
885
884
|
els.dashboardMeta.textContent =
|
|
886
885
|
sessions.length + (sessions.length === 1 ? ' execução' : ' execuções');
|
|
887
|
-
document.title = sessions.length
|
|
886
|
+
document.title = `${sessions.length} execuções · issue-flow`;
|
|
888
887
|
|
|
889
888
|
if (focusedId) {
|
|
890
889
|
const card = els.dashboard.querySelector(
|
|
891
|
-
|
|
890
|
+
`[data-session-id="${focusedId.replace(/"/g, '')}"]`,
|
|
892
891
|
);
|
|
893
892
|
if (card) card.focus();
|
|
894
893
|
}
|
|
@@ -922,12 +921,12 @@
|
|
|
922
921
|
}
|
|
923
922
|
|
|
924
923
|
function renderTitle(snapshot) {
|
|
925
|
-
const issue = snapshot.issue.number !== null ?
|
|
924
|
+
const issue = snapshot.issue.number !== null ? `#${snapshot.issue.number}` : '';
|
|
926
925
|
let prefix = '';
|
|
927
|
-
if (snapshot.status === 'running') prefix = snapshot.progress.percent
|
|
926
|
+
if (snapshot.status === 'running') prefix = `${snapshot.progress.percent}% · `;
|
|
928
927
|
else if (snapshot.status === 'completed') prefix = '✓ ';
|
|
929
928
|
else if (snapshot.status === 'failed') prefix = '✗ ';
|
|
930
|
-
document.title =
|
|
929
|
+
document.title = `${prefix + issue} · issue-flow`.replace(/^ · /, '');
|
|
931
930
|
}
|
|
932
931
|
|
|
933
932
|
// O h1 é a execução — número, título, e ao lado status, tempo decorrido e
|
|
@@ -936,7 +935,7 @@
|
|
|
936
935
|
const hasIssue = snapshot.issue.number !== null && snapshot.issue.number !== undefined;
|
|
937
936
|
if (hasIssue) {
|
|
938
937
|
els.issueLink.hidden = false;
|
|
939
|
-
els.issueLink.textContent =
|
|
938
|
+
els.issueLink.textContent = `#${snapshot.issue.number}`;
|
|
940
939
|
if (snapshot.issue.url) els.issueLink.href = snapshot.issue.url;
|
|
941
940
|
else els.issueLink.removeAttribute('href');
|
|
942
941
|
} else {
|
|
@@ -956,11 +955,11 @@
|
|
|
956
955
|
? 'criada pelo Issue Flow'
|
|
957
956
|
: 'origem da branch não informada';
|
|
958
957
|
els.branchLine.textContent = branch
|
|
959
|
-
?
|
|
958
|
+
? `${base ? `${branch} ← ${base}` : branch} · ${branchMode}`
|
|
960
959
|
: '';
|
|
961
960
|
|
|
962
961
|
els.statusBadge.textContent = STATUS_LABELS[snapshot.status] || snapshot.status;
|
|
963
|
-
els.statusBadge.className =
|
|
962
|
+
els.statusBadge.className = `badge status-${snapshot.status}`;
|
|
964
963
|
}
|
|
965
964
|
|
|
966
965
|
function renderAlerts(snapshot) {
|
|
@@ -973,8 +972,8 @@
|
|
|
973
972
|
if (!any) return;
|
|
974
973
|
|
|
975
974
|
const counts = [];
|
|
976
|
-
if (errors.length > 0) counts.push(errors.length
|
|
977
|
-
if (warnings.length > 0) counts.push(warnings.length
|
|
975
|
+
if (errors.length > 0) counts.push(`${errors.length} erro(s)`);
|
|
976
|
+
if (warnings.length > 0) counts.push(`${warnings.length} aviso(s)`);
|
|
978
977
|
if (counts.length > 0) {
|
|
979
978
|
els.alertsBody.appendChild(el('p', 'alert-count', counts.join(' · ')));
|
|
980
979
|
}
|
|
@@ -987,13 +986,13 @@
|
|
|
987
986
|
}
|
|
988
987
|
for (const log of errors.slice(-ALERT_PREVIEW)) {
|
|
989
988
|
const entry = el('div', 'alert-entry level-error');
|
|
990
|
-
entry.appendChild(el('span', 'mono', formatClock(log.at)
|
|
989
|
+
entry.appendChild(el('span', 'mono', `${formatClock(log.at)} `));
|
|
991
990
|
entry.appendChild(document.createTextNode(log.message));
|
|
992
991
|
els.alertsBody.appendChild(entry);
|
|
993
992
|
}
|
|
994
993
|
for (const log of warnings.slice(-ALERT_PREVIEW)) {
|
|
995
994
|
const entry = el('div', 'alert-entry level-warn');
|
|
996
|
-
entry.appendChild(el('span', 'mono', formatClock(log.at)
|
|
995
|
+
entry.appendChild(el('span', 'mono', `${formatClock(log.at)} `));
|
|
997
996
|
entry.appendChild(document.createTextNode(log.message));
|
|
998
997
|
els.alertsBody.appendChild(entry);
|
|
999
998
|
}
|
|
@@ -1012,7 +1011,7 @@
|
|
|
1012
1011
|
const state = issue.state || null;
|
|
1013
1012
|
const stateClass =
|
|
1014
1013
|
state === 'open' ? 'state-open' : state === 'closed' ? 'state-closed' : 'state-unknown';
|
|
1015
|
-
meta.appendChild(el('span',
|
|
1014
|
+
meta.appendChild(el('span', `badge ${stateClass}`, state || 'estado desconhecido'));
|
|
1016
1015
|
els.issueSummary.appendChild(meta);
|
|
1017
1016
|
|
|
1018
1017
|
const labels = issue.labels || [];
|
|
@@ -1054,7 +1053,7 @@
|
|
|
1054
1053
|
function renderProgress(snapshot) {
|
|
1055
1054
|
const progress = snapshot.progress;
|
|
1056
1055
|
els.progressBar.value = progress.percent;
|
|
1057
|
-
els.progressPercent.textContent = progress.percent
|
|
1056
|
+
els.progressPercent.textContent = `${progress.percent}%`;
|
|
1058
1057
|
const counters =
|
|
1059
1058
|
'Fases ' +
|
|
1060
1059
|
progress.phasesCompleted +
|
|
@@ -1065,7 +1064,7 @@
|
|
|
1065
1064
|
'/' +
|
|
1066
1065
|
progress.storiesTotal;
|
|
1067
1066
|
const totals = formatTotals(snapshot.metrics);
|
|
1068
|
-
els.progressCounters.textContent = totals ? counters
|
|
1067
|
+
els.progressCounters.textContent = totals ? `${counters} · ${totals}` : counters;
|
|
1069
1068
|
}
|
|
1070
1069
|
|
|
1071
1070
|
function nowRow(grid, label, value) {
|
|
@@ -1123,7 +1122,7 @@
|
|
|
1123
1122
|
resilience.cooldownUntil ? formatClock(resilience.cooldownUntil) : '—',
|
|
1124
1123
|
);
|
|
1125
1124
|
const activity = resilience.lastActivityAt
|
|
1126
|
-
? formatClock(resilience.lastActivityAt)
|
|
1125
|
+
? `${formatClock(resilience.lastActivityAt)} (${formatAgo(resilience.lastActivityAt)})`
|
|
1127
1126
|
: '—';
|
|
1128
1127
|
nowRow(grid, 'Última atividade', activity);
|
|
1129
1128
|
els.resilience.appendChild(grid);
|
|
@@ -1149,16 +1148,16 @@
|
|
|
1149
1148
|
// estar em versões diferentes; este é o único lugar onde as duas aparecem
|
|
1150
1149
|
// lado a lado, então a divergência é dita aqui.
|
|
1151
1150
|
const env = snapshot.environment;
|
|
1152
|
-
const runVersion = env
|
|
1151
|
+
const runVersion = env?.cliVersion ? env.cliVersion : null;
|
|
1153
1152
|
const runtime = el('dl', 'now-grid');
|
|
1154
|
-
const runtimeBits = [runVersion ?
|
|
1155
|
-
if (env
|
|
1156
|
-
if (env
|
|
1153
|
+
const runtimeBits = [runVersion ? `v${runVersion}` : 'versão não registrada'];
|
|
1154
|
+
if (env?.node) runtimeBits.push(env.node);
|
|
1155
|
+
if (env?.platform) runtimeBits.push(env.platform);
|
|
1157
1156
|
nowRow(runtime, 'Issue Flow (execução)', runtimeBits.join(' · '));
|
|
1158
1157
|
nowRow(
|
|
1159
1158
|
runtime,
|
|
1160
1159
|
'Monitor (este painel)',
|
|
1161
|
-
state.monitorVersion ?
|
|
1160
|
+
state.monitorVersion ? `v${state.monitorVersion}` : '—',
|
|
1162
1161
|
);
|
|
1163
1162
|
els.configuration.appendChild(runtime);
|
|
1164
1163
|
if (runVersion !== null && state.monitorVersion && runVersion !== state.monitorVersion) {
|
|
@@ -1197,10 +1196,10 @@
|
|
|
1197
1196
|
nowRow(summary, 'Precedência', list(config.precedence).join(' → '));
|
|
1198
1197
|
els.configuration.appendChild(summary);
|
|
1199
1198
|
|
|
1200
|
-
const liveRouting = state.configData
|
|
1199
|
+
const liveRouting = state.configData?.routing;
|
|
1201
1200
|
if (liveRouting) {
|
|
1202
1201
|
const routingSummary = el('dl', 'now-grid config-routing-summary');
|
|
1203
|
-
nowRow(routingSummary, 'Routing', liveRouting.mode
|
|
1202
|
+
nowRow(routingSummary, 'Routing', `${liveRouting.mode} · perfil ${liveRouting.profile}`);
|
|
1204
1203
|
nowRow(
|
|
1205
1204
|
routingSummary,
|
|
1206
1205
|
'Política',
|
|
@@ -1266,10 +1265,10 @@
|
|
|
1266
1265
|
phaseButton.addEventListener('click', () => openDrawer('phase', phase.phase));
|
|
1267
1266
|
row.appendChild(phaseButton);
|
|
1268
1267
|
const provider = el('select');
|
|
1269
|
-
provider.setAttribute('aria-label',
|
|
1268
|
+
provider.setAttribute('aria-label', `Harness para ${phase.phase}`);
|
|
1270
1269
|
fillProviderSelect(provider, phase.provider.value || 'claude');
|
|
1271
1270
|
const model = el('select');
|
|
1272
|
-
model.setAttribute('aria-label',
|
|
1271
|
+
model.setAttribute('aria-label', `Tier e modelo para ${phase.phase}`);
|
|
1273
1272
|
fillModelSelect(model, provider.value, phase.model.value || '');
|
|
1274
1273
|
provider.addEventListener('change', () => fillModelSelect(model, provider.value, ''));
|
|
1275
1274
|
const save = el('button', 'config-save', 'Salvar');
|
|
@@ -1324,7 +1323,7 @@
|
|
|
1324
1323
|
const form = el('form', 'config-form');
|
|
1325
1324
|
const provider = el('select');
|
|
1326
1325
|
provider.setAttribute('aria-label', 'Harness padrão para execuções futuras');
|
|
1327
|
-
for (const id of ['claude', 'codex', 'cursor', 'antigravity']) {
|
|
1326
|
+
for (const id of ['claude', 'codex', 'cursor', 'antigravity', 'opencode']) {
|
|
1328
1327
|
const option = el('option', null, id);
|
|
1329
1328
|
option.value = id;
|
|
1330
1329
|
provider.appendChild(option);
|
|
@@ -1365,7 +1364,7 @@
|
|
|
1365
1364
|
}
|
|
1366
1365
|
|
|
1367
1366
|
function catalog() {
|
|
1368
|
-
return list(state.configData
|
|
1367
|
+
return list(state.configData?.catalog);
|
|
1369
1368
|
}
|
|
1370
1369
|
|
|
1371
1370
|
function fillProviderSelect(select, selected) {
|
|
@@ -1380,7 +1379,7 @@
|
|
|
1380
1379
|
});
|
|
1381
1380
|
const providers = entries.length
|
|
1382
1381
|
? entries.map((entry) => entry.provider)
|
|
1383
|
-
: ['claude', 'codex', 'cursor', 'antigravity'];
|
|
1382
|
+
: ['claude', 'codex', 'cursor', 'antigravity', 'opencode'];
|
|
1384
1383
|
if (!providers.includes(selected)) providers.push(selected);
|
|
1385
1384
|
for (const provider of providers) {
|
|
1386
1385
|
const option = el('option', null, provider);
|
|
@@ -1396,9 +1395,9 @@
|
|
|
1396
1395
|
defaultOption.value = '';
|
|
1397
1396
|
select.appendChild(defaultOption);
|
|
1398
1397
|
const entry = catalog().find((candidate) => candidate.provider === provider);
|
|
1399
|
-
for (const model of list(entry
|
|
1398
|
+
for (const model of list(entry?.models)) {
|
|
1400
1399
|
if (!model.id) continue;
|
|
1401
|
-
const option = el('option', null, model.tier
|
|
1400
|
+
const option = el('option', null, `${model.tier} · ${model.id}`);
|
|
1402
1401
|
option.value = model.id;
|
|
1403
1402
|
select.appendChild(option);
|
|
1404
1403
|
}
|
|
@@ -1406,7 +1405,7 @@
|
|
|
1406
1405
|
selected &&
|
|
1407
1406
|
!Array.prototype.some.call(select.options, (option) => option.value === selected)
|
|
1408
1407
|
) {
|
|
1409
|
-
const current = el('option', null,
|
|
1408
|
+
const current = el('option', null, `configurado · ${selected}`);
|
|
1410
1409
|
current.value = selected;
|
|
1411
1410
|
select.appendChild(current);
|
|
1412
1411
|
}
|
|
@@ -1505,13 +1504,13 @@
|
|
|
1505
1504
|
meta.appendChild(
|
|
1506
1505
|
el(
|
|
1507
1506
|
'span',
|
|
1508
|
-
|
|
1507
|
+
`badge story-status-${storyStatus}`,
|
|
1509
1508
|
STORY_STATUS_LABELS[storyStatus] || storyStatus,
|
|
1510
1509
|
),
|
|
1511
1510
|
);
|
|
1512
1511
|
const dependencies = story.dependencies || [];
|
|
1513
1512
|
if (dependencies.length > 0) {
|
|
1514
|
-
meta.appendChild(el('span', 'muted story-deps',
|
|
1513
|
+
meta.appendChild(el('span', 'muted story-deps', `depende de: ${dependencies.join(', ')}`));
|
|
1515
1514
|
}
|
|
1516
1515
|
main.appendChild(meta);
|
|
1517
1516
|
|
|
@@ -1519,11 +1518,11 @@
|
|
|
1519
1518
|
const duration = metric(story.durationSeconds);
|
|
1520
1519
|
const stageLabel = STORY_STAGE_LABELS[storyStage] || storyStage;
|
|
1521
1520
|
const stageText = story.stageSince
|
|
1522
|
-
? stageLabel
|
|
1521
|
+
? `${stageLabel} ${formatAgo(story.stageSince)}`
|
|
1523
1522
|
: stageLabel;
|
|
1524
1523
|
const side = itemSideText([
|
|
1525
1524
|
stageText,
|
|
1526
|
-
story.completedAt ?
|
|
1525
|
+
story.completedAt ? `concluída ${formatClock(story.completedAt)}` : '',
|
|
1527
1526
|
duration !== null ? formatDuration(duration) : '',
|
|
1528
1527
|
formatUsage(story),
|
|
1529
1528
|
]);
|
|
@@ -1556,7 +1555,7 @@
|
|
|
1556
1555
|
card.appendChild(el('span', 'kanban-card-title', story.title));
|
|
1557
1556
|
if (story.description) card.appendChild(el('span', 'kanban-card-desc', story.description));
|
|
1558
1557
|
card.appendChild(
|
|
1559
|
-
el('span',
|
|
1558
|
+
el('span', `badge story-status-${story.status}`, STORY_STATUS_LABELS[story.status]),
|
|
1560
1559
|
);
|
|
1561
1560
|
card.addEventListener('click', () => openDrawer('story', story.id));
|
|
1562
1561
|
return card;
|
|
@@ -1601,10 +1600,10 @@
|
|
|
1601
1600
|
if (cost.status === 'reported' || cost.status === 'estimated') {
|
|
1602
1601
|
return formatCost(cost.amount, cost.status === 'estimated');
|
|
1603
1602
|
}
|
|
1604
|
-
return cost.reason ?
|
|
1603
|
+
return cost.reason ? `não informado (${cost.reason})` : 'não informado';
|
|
1605
1604
|
}
|
|
1606
1605
|
|
|
1607
|
-
function renderExecutionHistory(
|
|
1606
|
+
function renderExecutionHistory(_snapshot, executions) {
|
|
1608
1607
|
drawerSection('Tentativas, revisões e correções', (body) => {
|
|
1609
1608
|
if (executions.length === 0) {
|
|
1610
1609
|
body.appendChild(el('p', 'empty', 'Nenhuma invocação associada.'));
|
|
@@ -1617,7 +1616,7 @@
|
|
|
1617
1616
|
title.appendChild(
|
|
1618
1617
|
el(
|
|
1619
1618
|
'span',
|
|
1620
|
-
|
|
1619
|
+
`badge status-${execution.status === 'completed' ? 'completed' : execution.status}`,
|
|
1621
1620
|
execution.status,
|
|
1622
1621
|
),
|
|
1623
1622
|
);
|
|
@@ -1625,7 +1624,7 @@
|
|
|
1625
1624
|
el(
|
|
1626
1625
|
'strong',
|
|
1627
1626
|
null,
|
|
1628
|
-
execution.purpose
|
|
1627
|
+
`${execution.purpose} · tentativa ${execution.attempt} · ${execution.trigger}`,
|
|
1629
1628
|
),
|
|
1630
1629
|
);
|
|
1631
1630
|
item.appendChild(title);
|
|
@@ -1650,7 +1649,7 @@
|
|
|
1650
1649
|
nowRow(grid, 'Tokens', formatUsage(execution.usage || {}) || '—');
|
|
1651
1650
|
nowRow(grid, 'Custo', executionCost(execution));
|
|
1652
1651
|
if (execution.correctionCycle)
|
|
1653
|
-
nowRow(grid, 'Correção',
|
|
1652
|
+
nowRow(grid, 'Correção', `ciclo ${execution.correctionCycle}`);
|
|
1654
1653
|
if (execution.verdict?.status) nowRow(grid, 'Veredito', execution.verdict.status);
|
|
1655
1654
|
item.appendChild(grid);
|
|
1656
1655
|
if (execution.failure?.message)
|
|
@@ -1668,7 +1667,7 @@
|
|
|
1668
1667
|
);
|
|
1669
1668
|
drawerSection('Saída do processo', (body) => {
|
|
1670
1669
|
const details = el('details', 'process-output');
|
|
1671
|
-
const summary = el('summary', null, logs.length
|
|
1670
|
+
const summary = el('summary', null, `${logs.length} linha(s) sanitizada(s)`);
|
|
1672
1671
|
details.appendChild(summary);
|
|
1673
1672
|
if (logs.length === 0) {
|
|
1674
1673
|
details.appendChild(el('p', 'empty', 'Nenhuma saída capturada.'));
|
|
@@ -1676,7 +1675,7 @@
|
|
|
1676
1675
|
const output = el('pre', 'process-output-body');
|
|
1677
1676
|
output.textContent = logs
|
|
1678
1677
|
.slice(-200)
|
|
1679
|
-
.map((entry) => formatClock(entry.at)
|
|
1678
|
+
.map((entry) => `${formatClock(entry.at)} ${entry.message}`)
|
|
1680
1679
|
.join('\n');
|
|
1681
1680
|
details.appendChild(output);
|
|
1682
1681
|
}
|
|
@@ -1695,12 +1694,12 @@
|
|
|
1695
1694
|
drawerSection('Diagnóstico global persistente', (body) => {
|
|
1696
1695
|
const details = el('details', 'process-output');
|
|
1697
1696
|
details.appendChild(
|
|
1698
|
-
el('summary', null, entries.length
|
|
1697
|
+
el('summary', null, `${entries.length} registro(s) em ~/.issue-flow/logs`),
|
|
1699
1698
|
);
|
|
1700
1699
|
const output = el('pre', 'process-output-body');
|
|
1701
1700
|
output.textContent = entries
|
|
1702
1701
|
.slice(0, 200)
|
|
1703
|
-
.map((entry) => formatClock(entry.timestamp)
|
|
1702
|
+
.map((entry) => `${formatClock(entry.timestamp)} ${entry.level} ${entry.message}`)
|
|
1704
1703
|
.join('\n');
|
|
1705
1704
|
details.appendChild(output);
|
|
1706
1705
|
body.appendChild(details);
|
|
@@ -1722,8 +1721,8 @@
|
|
|
1722
1721
|
|
|
1723
1722
|
clear(els.drawerBody);
|
|
1724
1723
|
if (kind === 'phase') {
|
|
1725
|
-
els.drawerTitle.textContent =
|
|
1726
|
-
els.drawerBody.appendChild(el('span',
|
|
1724
|
+
els.drawerTitle.textContent = `Fase · ${phase.name}`;
|
|
1725
|
+
els.drawerBody.appendChild(el('span', `badge status-${phase.status}`, phase.status));
|
|
1727
1726
|
const grid = el('dl', 'now-grid drawer-summary-grid');
|
|
1728
1727
|
nowRow(grid, 'Início', phase.startedAt ? formatClock(phase.startedAt) : '—');
|
|
1729
1728
|
nowRow(grid, 'Fim', phase.endedAt ? formatClock(phase.endedAt) : '—');
|
|
@@ -1750,13 +1749,13 @@
|
|
|
1750
1749
|
return;
|
|
1751
1750
|
}
|
|
1752
1751
|
|
|
1753
|
-
els.drawerTitle.textContent = story.id
|
|
1752
|
+
els.drawerTitle.textContent = `${story.id} · ${story.title}`;
|
|
1754
1753
|
els.drawerBody.appendChild(
|
|
1755
|
-
el('span',
|
|
1754
|
+
el('span', `badge story-status-${story.status}`, STORY_STATUS_LABELS[story.status]),
|
|
1756
1755
|
);
|
|
1757
1756
|
|
|
1758
1757
|
const timing = itemSideText([
|
|
1759
|
-
story.completedAt ?
|
|
1758
|
+
story.completedAt ? `concluída ${formatClock(story.completedAt)}` : '',
|
|
1760
1759
|
metric(story.durationSeconds) !== null ? formatDuration(story.durationSeconds) : '',
|
|
1761
1760
|
]);
|
|
1762
1761
|
if (timing) els.drawerBody.appendChild(el('p', 'muted drawer-timing', timing));
|
|
@@ -1804,7 +1803,7 @@
|
|
|
1804
1803
|
item.appendChild(
|
|
1805
1804
|
document.createTextNode(
|
|
1806
1805
|
(STORY_STAGE_LABELS[entry.stage] || entry.stage || '') +
|
|
1807
|
-
(entry.detail ?
|
|
1806
|
+
(entry.detail ? ` · ${entry.detail}` : ''),
|
|
1808
1807
|
),
|
|
1809
1808
|
);
|
|
1810
1809
|
entries.appendChild(item);
|
|
@@ -1845,7 +1844,7 @@
|
|
|
1845
1844
|
// referência guardada na abertura.
|
|
1846
1845
|
const card =
|
|
1847
1846
|
selected && selected.kind === 'story'
|
|
1848
|
-
? els.kanban.querySelector(
|
|
1847
|
+
? els.kanban.querySelector(`[data-story-id="${selected.id}"]`)
|
|
1849
1848
|
: null;
|
|
1850
1849
|
if (card) card.focus();
|
|
1851
1850
|
}
|
|
@@ -1860,7 +1859,7 @@
|
|
|
1860
1859
|
for (const commit of snapshot.git.commits) {
|
|
1861
1860
|
const item = el('li');
|
|
1862
1861
|
const hash = repo
|
|
1863
|
-
? link(repo
|
|
1862
|
+
? link(`${repo}/commit/${commit.hash}`, commit.hash, 'mono commit-hash')
|
|
1864
1863
|
: el('span', 'mono commit-hash', commit.hash);
|
|
1865
1864
|
item.appendChild(hash);
|
|
1866
1865
|
const subject = el('div', 'item-main item-title', commit.subject);
|
|
@@ -1880,7 +1879,7 @@
|
|
|
1880
1879
|
} else {
|
|
1881
1880
|
for (const pr of snapshot.pullRequests) {
|
|
1882
1881
|
const item = el('li');
|
|
1883
|
-
item.appendChild(link(pr.url,
|
|
1882
|
+
item.appendChild(link(pr.url, `#${pr.number}`));
|
|
1884
1883
|
item.appendChild(el('div', 'item-main item-title', pr.title));
|
|
1885
1884
|
els.pullRequests.appendChild(item);
|
|
1886
1885
|
}
|
|
@@ -1897,7 +1896,7 @@
|
|
|
1897
1896
|
}
|
|
1898
1897
|
// Mais recentes primeiro: monitoramento lê o topo, sem gerenciar scroll.
|
|
1899
1898
|
for (const entry of entries.slice().reverse()) {
|
|
1900
|
-
const item = el('li',
|
|
1899
|
+
const item = el('li', `level-${entry.level}`);
|
|
1901
1900
|
item.appendChild(el('span', 'log-time', formatClock(entry.at)));
|
|
1902
1901
|
item.appendChild(el('span', 'log-level', entry.level));
|
|
1903
1902
|
item.appendChild(el('span', 'log-message', entry.message));
|
|
@@ -1918,27 +1917,27 @@
|
|
|
1918
1917
|
case 'session:start':
|
|
1919
1918
|
return 'Sessão iniciada';
|
|
1920
1919
|
case 'session:end':
|
|
1921
|
-
return
|
|
1920
|
+
return `Sessão encerrada: ${event.status}`;
|
|
1922
1921
|
case 'phase:start':
|
|
1923
|
-
return
|
|
1922
|
+
return `Fase iniciada: ${event.phase}`;
|
|
1924
1923
|
case 'phase:end':
|
|
1925
|
-
return
|
|
1924
|
+
return `Fase encerrada: ${event.phase}${event.success ? ' (ok)' : ' (falhou)'}`;
|
|
1926
1925
|
case 'iteration:start':
|
|
1927
|
-
return
|
|
1926
|
+
return `Iteração ${event.iteration} iniciada`;
|
|
1928
1927
|
case 'iteration:end':
|
|
1929
|
-
return
|
|
1928
|
+
return `Iteração ${event.iteration} encerrada`;
|
|
1930
1929
|
case 'retry':
|
|
1931
|
-
return
|
|
1930
|
+
return `Retry ${event.attempt}${event.kind ? `: ${event.kind}` : ''}`;
|
|
1932
1931
|
case 'agent:attempt':
|
|
1933
|
-
return
|
|
1932
|
+
return `Tentativa ${event.attempt} com ${event.provider}`;
|
|
1934
1933
|
case 'agent:activity':
|
|
1935
|
-
return
|
|
1934
|
+
return `Atividade recebida de ${event.provider}`;
|
|
1936
1935
|
case 'agent:result':
|
|
1937
1936
|
return (
|
|
1938
1937
|
event.provider +
|
|
1939
1938
|
(event.success
|
|
1940
1939
|
? ' concluiu a tentativa'
|
|
1941
|
-
:
|
|
1940
|
+
: ` falhou: ${event.failureKind || 'desconhecida'}`)
|
|
1942
1941
|
);
|
|
1943
1942
|
case 'failover':
|
|
1944
1943
|
return (
|
|
@@ -1946,10 +1945,10 @@
|
|
|
1946
1945
|
event.from +
|
|
1947
1946
|
' para ' +
|
|
1948
1947
|
event.to +
|
|
1949
|
-
(event.reason ?
|
|
1948
|
+
(event.reason ? `: ${event.reason}` : '')
|
|
1950
1949
|
);
|
|
1951
1950
|
case 'correction:cycle':
|
|
1952
|
-
return
|
|
1951
|
+
return `Ciclo de correção ${event.cycle}/${event.maxCycles}`;
|
|
1953
1952
|
case 'log':
|
|
1954
1953
|
return event.message;
|
|
1955
1954
|
default:
|
|
@@ -1960,7 +1959,7 @@
|
|
|
1960
1959
|
function renderHistory() {
|
|
1961
1960
|
clear(els.history);
|
|
1962
1961
|
const entries = state.events.filter((entry) => {
|
|
1963
|
-
const type = entry
|
|
1962
|
+
const type = entry?.event?.type;
|
|
1964
1963
|
if (!type) return false;
|
|
1965
1964
|
if (state.historyFilter === 'resilience') return RESILIENCE_EVENTS.has(type);
|
|
1966
1965
|
if (state.historyFilter === 'pipeline') return !RESILIENCE_EVENTS.has(type);
|
|
@@ -1982,8 +1981,8 @@
|
|
|
1982
1981
|
|
|
1983
1982
|
function renderMeta(snapshot) {
|
|
1984
1983
|
const parts = [];
|
|
1985
|
-
if (snapshot.sessionId) parts.push(
|
|
1986
|
-
if (snapshot.updatedAt) parts.push(
|
|
1984
|
+
if (snapshot.sessionId) parts.push(`execução ${snapshot.sessionId}`);
|
|
1985
|
+
if (snapshot.updatedAt) parts.push(`atualizado ${formatClock(snapshot.updatedAt)}`);
|
|
1987
1986
|
parts.push('somente leitura');
|
|
1988
1987
|
els.sessionMeta.textContent = parts.join(' · ');
|
|
1989
1988
|
}
|
|
@@ -2006,7 +2005,7 @@
|
|
|
2006
2005
|
const estimate = snapshot.estimatedRemainingSeconds;
|
|
2007
2006
|
if (snapshot.status === 'running' && estimate !== null) {
|
|
2008
2007
|
els.estimate.hidden = false;
|
|
2009
|
-
els.estimate.textContent =
|
|
2008
|
+
els.estimate.textContent = `~${formatDuration(estimate)} restantes (estimativa)`;
|
|
2010
2009
|
} else {
|
|
2011
2010
|
els.estimate.hidden = true;
|
|
2012
2011
|
}
|
|
@@ -2087,7 +2086,7 @@
|
|
|
2087
2086
|
if (stored === null && Number.isFinite(suggested) && suggested > 0) {
|
|
2088
2087
|
state.refreshSeconds = suggested;
|
|
2089
2088
|
}
|
|
2090
|
-
} catch (
|
|
2089
|
+
} catch (_err) {
|
|
2091
2090
|
// Sem /api/health segue o default local (5s).
|
|
2092
2091
|
}
|
|
2093
2092
|
if (stored !== null) state.refreshSeconds = stored;
|