wendkeep 0.12.0 → 0.13.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/CHANGELOG.md +12 -0
- package/hooks/subagent-usage.mjs +9 -2
- package/package.json +1 -1
- package/src/cost.mjs +8 -3
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,17 @@ All notable changes to **wendkeep** are documented here. Format based on
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this project follows
|
|
5
5
|
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.13.0] — 2026-07-06
|
|
8
|
+
|
|
9
|
+
Cost intelligence: waste + average.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- **Wasted-spend tracking:** a killed/failed workflow run's subagent cost is now recorded per
|
|
13
|
+
session (`subagents_wasted_usd` + a line in the note's `## Subagents & Workflows`) and rolled
|
|
14
|
+
up by `wendkeep cost` (`desperdiçado (runs killed/failed): $X`). Money burned on aborted runs
|
|
15
|
+
was invisible before.
|
|
16
|
+
- **`wendkeep cost` per-session average** (`$/sessão`) alongside the vault total.
|
|
17
|
+
|
|
7
18
|
## [0.12.0] — 2026-07-06
|
|
8
19
|
|
|
9
20
|
Deeper subagent/workflow telemetry.
|
|
@@ -261,6 +272,7 @@ Initial release — the capture engine, extracted from a system in daily product
|
|
|
261
272
|
- `wendkeep init` (cross-platform installer) + optional `@bitbonsai/mcpvault` MCP server.
|
|
262
273
|
|
|
263
274
|
<!-- Only v0.4.0+ is tagged in git (history starts here); older versions link to npm. -->
|
|
275
|
+
[0.13.0]: https://github.com/rogersialves/wendkeep/releases/tag/v0.13.0
|
|
264
276
|
[0.12.0]: https://github.com/rogersialves/wendkeep/releases/tag/v0.12.0
|
|
265
277
|
[0.11.0]: https://github.com/rogersialves/wendkeep/releases/tag/v0.11.0
|
|
266
278
|
[0.10.0]: https://github.com/rogersialves/wendkeep/releases/tag/v0.10.0
|
package/hooks/subagent-usage.mjs
CHANGED
|
@@ -143,10 +143,15 @@ export function collectSubagentUsage(sessionDir) {
|
|
|
143
143
|
};
|
|
144
144
|
});
|
|
145
145
|
|
|
146
|
+
// Wasted spend: cost of workflow runs that did not complete (killed/failed/…). The
|
|
147
|
+
// subagents that ran before the kill still cost money — this makes that visible.
|
|
148
|
+
const WASTE = /^(killed|failed|error|aborted|cancel(l)?ed)$/i;
|
|
149
|
+
const wasted = round4(workflows.filter((w) => WASTE.test(w.status)).reduce((s, w) => s + w.cost, 0));
|
|
150
|
+
|
|
146
151
|
return {
|
|
147
152
|
subagents,
|
|
148
153
|
workflows,
|
|
149
|
-
aggregate: { count, calls, tokens: tokensTotal(usageAgg), cost: round4(cost), usage: usageAgg, tools: [...allTools] },
|
|
154
|
+
aggregate: { count, calls, tokens: tokensTotal(usageAgg), cost: round4(cost), wasted, usage: usageAgg, tools: [...allTools] },
|
|
150
155
|
};
|
|
151
156
|
}
|
|
152
157
|
|
|
@@ -167,13 +172,14 @@ export function renderSubagentSection(c) {
|
|
|
167
172
|
const rows = c.subagents
|
|
168
173
|
.map((s) => `| ${s.id} | ${s.agentType || '-'} | ${s.workflow || '-'} | ${s.model} | ${s.tools} | ${fmt(s.tokens)} | ${usd(s.cost)} |`)
|
|
169
174
|
.join('\n');
|
|
175
|
+
const wasteLine = a.wasted ? `\n- **Desperdiçado (runs killed/failed):** ${usd(a.wasted)}` : '';
|
|
170
176
|
return `## Subagents & Workflows
|
|
171
177
|
|
|
172
178
|
> Custo de subagents/workflows desta sessão — NÃO incluído no total principal acima.
|
|
173
179
|
|
|
174
180
|
- **Subagents:** ${a.count} · ${a.calls} chamadas · ${fmt(a.tokens)} tokens · ${usd(a.cost)}
|
|
175
181
|
- **Workflows:** ${wf}
|
|
176
|
-
- **Tools (subagents):** ${tools}
|
|
182
|
+
- **Tools (subagents):** ${tools}${wasteLine}
|
|
177
183
|
|
|
178
184
|
<details><summary>Por subagent (${a.count})</summary>
|
|
179
185
|
|
|
@@ -220,6 +226,7 @@ export function upsertSubagentUsage(sessionPath, transcriptPath) {
|
|
|
220
226
|
content = setFrontmatterField(content, 'subagents_tokens_total', a.tokens);
|
|
221
227
|
content = setFrontmatterField(content, 'subagents_custo_usd', a.cost);
|
|
222
228
|
content = setFrontmatterField(content, 'subagents_tools', `"${(a.tools || []).join(', ')}"`);
|
|
229
|
+
content = setFrontmatterField(content, 'subagents_wasted_usd', a.wasted || 0);
|
|
223
230
|
content = setFrontmatterField(content, 'tokens_total_incl_subagents', frontmatterNumber(content, 'tokens_total') + a.tokens);
|
|
224
231
|
content = upsertSection(content, '## Subagents & Workflows', renderSubagentSection(collected));
|
|
225
232
|
writeFileSync(sessionPath, content, 'utf8');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wendkeep",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "A persistent-memory harness for AI coding agents on your Obsidian vault: turn-by-turn session capture plus a native, zero-dependency spec→change→verify→archive loop (sensor-gated, independent verdict, mutation discrimination). Local-first, agent-agnostic (Claude Code, Codex, Cursor…).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/cost.mjs
CHANGED
|
@@ -21,6 +21,7 @@ export function parseSessionCost(content) {
|
|
|
21
21
|
model: fmValue(content, 'custo_modelo_label') || fmValue(content, 'modelo') || '?',
|
|
22
22
|
mainCost: Number(fmValue(content, 'custo_modelo_usd')) || 0,
|
|
23
23
|
subCost: Number(fmValue(content, 'subagents_custo_usd')) || 0,
|
|
24
|
+
wasted: Number(fmValue(content, 'subagents_wasted_usd')) || 0,
|
|
24
25
|
tokens: Number(fmValue(content, 'tokens_total')) || 0,
|
|
25
26
|
subTokens: Number(fmValue(content, 'subagents_tokens_total')) || 0,
|
|
26
27
|
};
|
|
@@ -31,19 +32,22 @@ export function aggregateCosts(entries) {
|
|
|
31
32
|
const byModel = {};
|
|
32
33
|
let main = 0;
|
|
33
34
|
let sub = 0;
|
|
35
|
+
let wasted = 0;
|
|
34
36
|
let tokens = 0;
|
|
35
37
|
let subTokens = 0;
|
|
36
38
|
for (const e of entries) {
|
|
37
|
-
main += e.mainCost; sub += e.subCost; tokens += e.tokens; subTokens += e.subTokens;
|
|
39
|
+
main += e.mainCost; sub += e.subCost; wasted += e.wasted || 0; tokens += e.tokens; subTokens += e.subTokens;
|
|
38
40
|
const d = e.date || '?';
|
|
39
41
|
(byDay[d] = byDay[d] || { cost: 0, count: 0 }).cost += e.mainCost + e.subCost;
|
|
40
42
|
byDay[d].count += 1;
|
|
41
43
|
(byModel[e.model] = byModel[e.model] || { cost: 0, count: 0 }).cost += e.mainCost + e.subCost;
|
|
42
44
|
byModel[e.model].count += 1;
|
|
43
45
|
}
|
|
46
|
+
const total = main + sub;
|
|
44
47
|
return {
|
|
45
48
|
count: entries.length,
|
|
46
|
-
main: round4(main), sub: round4(sub), total: round4(
|
|
49
|
+
main: round4(main), sub: round4(sub), total: round4(total), wasted: round4(wasted),
|
|
50
|
+
avg: round4(entries.length ? total / entries.length : 0),
|
|
47
51
|
tokens, subTokens,
|
|
48
52
|
byDay: Object.entries(byDay).sort().map(([date, v]) => ({ date, cost: round4(v.cost), count: v.count })),
|
|
49
53
|
byModel: Object.entries(byModel).sort((a, b) => b[1].cost - a[1].cost).map(([model, v]) => ({ model, cost: round4(v.cost), count: v.count })),
|
|
@@ -93,8 +97,9 @@ export function runCost(argv) {
|
|
|
93
97
|
|
|
94
98
|
if (argv.includes('--json')) { process.stdout.write(`${JSON.stringify(agg, null, 2)}\n`); process.exit(0); }
|
|
95
99
|
|
|
96
|
-
process.stdout.write(`Custo total (vault): ${usd(agg.total)} — ${agg.count} sessão(ões)\n`);
|
|
100
|
+
process.stdout.write(`Custo total (vault): ${usd(agg.total)} — ${agg.count} sessão(ões) · ${usd(agg.avg)}/sessão\n`);
|
|
97
101
|
process.stdout.write(` main: ${usd(agg.main)} · subagents: ${usd(agg.sub)}\n`);
|
|
102
|
+
if (agg.wasted) process.stdout.write(` desperdiçado (runs killed/failed): ${usd(agg.wasted)}\n`);
|
|
98
103
|
if (agg.byModel.length) {
|
|
99
104
|
process.stdout.write('\nPor modelo:\n');
|
|
100
105
|
for (const m of agg.byModel) process.stdout.write(` ${m.model.padEnd(20)} ${usd(m.cost)} (${m.count})\n`);
|