gitdone-agent 0.6.6 → 0.6.7
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/index.js +68 -7
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -547,12 +547,15 @@ async function reportCommandResult(cfg, id, status, result) {
|
|
|
547
547
|
}
|
|
548
548
|
|
|
549
549
|
// Post a batch of console events (and optional lifecycle status) for an AiRun.
|
|
550
|
-
|
|
550
|
+
// `usage` is sent once on the final (done/error) post so the server can record
|
|
551
|
+
// how many tokens the run cost.
|
|
552
|
+
async function postRunEvents(cfg, runId, events, status, result, usage) {
|
|
551
553
|
await api(cfg, '/api/v1/agent/ai-run/events', {
|
|
552
554
|
runId,
|
|
553
555
|
events,
|
|
554
556
|
...(status ? { status } : {}),
|
|
555
557
|
...(result !== undefined ? { result } : {}),
|
|
558
|
+
...(usage ? { usage } : {}),
|
|
556
559
|
}).catch((e) => log(`✗ ai-run events post failed: ${e.message}`))
|
|
557
560
|
}
|
|
558
561
|
|
|
@@ -575,7 +578,15 @@ async function postSessionEvents(cfg, sessionId, events, status, claudeSessionId
|
|
|
575
578
|
// With `--include-partial-messages`, Claude also emits `stream_event` lines
|
|
576
579
|
// carrying incremental text deltas — onDelta gets those so chat sessions can
|
|
577
580
|
// show the reply being written live (gd-302).
|
|
578
|
-
|
|
581
|
+
// "12.3k" / "1.2M" compaction for the console token summary line.
|
|
582
|
+
function fmtTokens(n) {
|
|
583
|
+
n = Number(n) || 0
|
|
584
|
+
if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`
|
|
585
|
+
if (n >= 1_000) return `${(n / 1_000).toFixed(1)}k`
|
|
586
|
+
return String(n)
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
function parseStreamLine(line, push, onInit, onDelta, onMeta) {
|
|
579
590
|
let ev
|
|
580
591
|
try { ev = JSON.parse(line) } catch { return }
|
|
581
592
|
if (ev.type === 'system') {
|
|
@@ -583,6 +594,8 @@ function parseStreamLine(line, push, onInit, onDelta) {
|
|
|
583
594
|
push('SYSTEM', `Сесия стартирана${ev.model ? ` (${ev.model})` : ''}.`)
|
|
584
595
|
// Surface Claude's own session id so chat sessions can --resume it.
|
|
585
596
|
if (ev.session_id && typeof onInit === 'function') onInit(ev.session_id)
|
|
597
|
+
// Remember which model ran, for the token/cost record (gd-334).
|
|
598
|
+
if (ev.model && typeof onMeta === 'function') onMeta({ model: ev.model })
|
|
586
599
|
}
|
|
587
600
|
return
|
|
588
601
|
}
|
|
@@ -607,8 +620,40 @@ function parseStreamLine(line, push, onInit, onDelta) {
|
|
|
607
620
|
}
|
|
608
621
|
return
|
|
609
622
|
}
|
|
610
|
-
if (ev.type === 'result'
|
|
611
|
-
push('SYSTEM', `Резултат: ${ev.subtype}`)
|
|
623
|
+
if (ev.type === 'result') {
|
|
624
|
+
if (ev.subtype && ev.subtype !== 'success') push('SYSTEM', `Резултат: ${ev.subtype}`)
|
|
625
|
+
// claude's final result carries cumulative token usage + its own cost.
|
|
626
|
+
// Prefer `modelUsage` (summed over every model/subagent turn) which is the
|
|
627
|
+
// true cumulative; top-level `usage` is often just the last turn. Fall back
|
|
628
|
+
// to `usage` when modelUsage is absent (older CLI).
|
|
629
|
+
if (typeof onMeta === 'function' && (ev.modelUsage || ev.usage || typeof ev.total_cost_usd === 'number')) {
|
|
630
|
+
let usage
|
|
631
|
+
let model
|
|
632
|
+
if (ev.modelUsage && typeof ev.modelUsage === 'object') {
|
|
633
|
+
const acc = { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheCreateTokens: 0 }
|
|
634
|
+
for (const [name, mu] of Object.entries(ev.modelUsage)) {
|
|
635
|
+
if (!model) model = name
|
|
636
|
+
acc.inputTokens += mu.inputTokens ?? mu.input_tokens ?? 0
|
|
637
|
+
acc.outputTokens += mu.outputTokens ?? mu.output_tokens ?? 0
|
|
638
|
+
acc.cacheReadTokens += mu.cacheReadInputTokens ?? mu.cache_read_input_tokens ?? 0
|
|
639
|
+
acc.cacheCreateTokens += mu.cacheCreationInputTokens ?? mu.cache_creation_input_tokens ?? 0
|
|
640
|
+
}
|
|
641
|
+
usage = acc
|
|
642
|
+
} else if (ev.usage) {
|
|
643
|
+
const u = ev.usage
|
|
644
|
+
usage = {
|
|
645
|
+
inputTokens: u.input_tokens ?? 0,
|
|
646
|
+
outputTokens: u.output_tokens ?? 0,
|
|
647
|
+
cacheReadTokens: u.cache_read_input_tokens ?? 0,
|
|
648
|
+
cacheCreateTokens: u.cache_creation_input_tokens ?? 0,
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
onMeta({
|
|
652
|
+
...(usage ? { usage } : {}),
|
|
653
|
+
...(model ? { model } : {}),
|
|
654
|
+
costUsd: typeof ev.total_cost_usd === 'number' ? ev.total_cost_usd : undefined,
|
|
655
|
+
})
|
|
656
|
+
}
|
|
612
657
|
}
|
|
613
658
|
}
|
|
614
659
|
|
|
@@ -799,6 +844,15 @@ function runAiCommand(cfg, cmd, repoPath) {
|
|
|
799
844
|
const push = (kind, text) => { if (text != null && String(text) !== '') pending.push({ kind, text: String(text) }) }
|
|
800
845
|
const timer = setInterval(flush, 800)
|
|
801
846
|
|
|
847
|
+
// Accumulate model + token usage across the stream (model from init, usage
|
|
848
|
+
// from the final result event) to report once on exit (gd-334).
|
|
849
|
+
const meta = { model: undefined, usage: undefined, costUsd: undefined }
|
|
850
|
+
const onMeta = (m) => {
|
|
851
|
+
if (m.model) meta.model = m.model
|
|
852
|
+
if (m.usage) meta.usage = m.usage
|
|
853
|
+
if (typeof m.costUsd === 'number') meta.costUsd = m.costUsd
|
|
854
|
+
}
|
|
855
|
+
|
|
802
856
|
log(`▶ ai_run ${runId} @ ${repoPath} via ${claudePath}`)
|
|
803
857
|
postRunEvents(cfg, runId, [{ kind: 'SYSTEM', text: `Стартиране на Claude Code в ${repoPath}…` }], 'running')
|
|
804
858
|
|
|
@@ -827,21 +881,28 @@ function runAiCommand(cfg, cmd, repoPath) {
|
|
|
827
881
|
while ((nl = buf.indexOf('\n')) >= 0) {
|
|
828
882
|
const line = buf.slice(0, nl).trim()
|
|
829
883
|
buf = buf.slice(nl + 1)
|
|
830
|
-
if (line) parseStreamLine(line, push)
|
|
884
|
+
if (line) parseStreamLine(line, push, undefined, undefined, onMeta)
|
|
831
885
|
}
|
|
832
886
|
})
|
|
833
887
|
child.stderr.on('data', (d) => { const s = d.toString().trim(); if (s) push('SYSTEM', s) })
|
|
834
888
|
child.on('error', (err) => push('SYSTEM', `Процесна грешка: ${err.message}`))
|
|
835
889
|
child.on('close', async (code) => {
|
|
836
890
|
clearInterval(timer)
|
|
837
|
-
if (buf.trim()) parseStreamLine(buf.trim(), push)
|
|
891
|
+
if (buf.trim()) parseStreamLine(buf.trim(), push, undefined, undefined, onMeta)
|
|
838
892
|
await flush()
|
|
839
893
|
const ok = code === 0
|
|
894
|
+
// Build the usage payload + a console summary line from what we saw.
|
|
895
|
+
const usage = meta.usage
|
|
896
|
+
? { model: meta.model, ...meta.usage, ...(typeof meta.costUsd === 'number' ? { costUsd: meta.costUsd } : {}) }
|
|
897
|
+
: undefined
|
|
898
|
+
const events = [{ kind: 'SYSTEM', text: ok ? '✓ Готово.' : `✗ Процесът приключи с код ${code}.` }]
|
|
899
|
+
if (usage) events.push({ kind: 'SYSTEM', text: `📊 Токени: ${fmtTokens(usage.inputTokens)} вход · ${fmtTokens(usage.outputTokens)} изход${usage.cacheReadTokens ? ` · ${fmtTokens(usage.cacheReadTokens)} кеш` : ''}${typeof usage.costUsd === 'number' ? ` · $${usage.costUsd.toFixed(4)}` : ''}` })
|
|
840
900
|
await postRunEvents(
|
|
841
901
|
cfg, runId,
|
|
842
|
-
|
|
902
|
+
events,
|
|
843
903
|
ok ? 'done' : 'error',
|
|
844
904
|
ok ? 'ok' : `exit ${code}`,
|
|
905
|
+
usage,
|
|
845
906
|
)
|
|
846
907
|
reportCommandResult(cfg, cmd.id, ok ? 'done' : 'error', `exit ${code}`)
|
|
847
908
|
log(`■ ai_run ${runId} приключи (code ${code})`)
|