@dtlabs/ai-toolkit 0.6.0 → 0.8.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/.claude/agents/define-feature.md +67 -1
- package/.claude/agents/developer-testing.md +4 -4
- package/.claude/agents/install-toolkit.md +34 -0
- package/.claude/workflows/pm-phase1.js +78 -0
- package/.claude/workflows/pm-phase2.js +103 -26
- package/.claude/workflows/pm-phase3.js +152 -17
- package/CHANGELOG.md +51 -0
- package/bin/cli.js +428 -3
- package/docs/token-pricing.json +21 -0
- package/package.json +1 -1
- package/docs/token-optimization-backlog.md +0 -115
- package/docs/token-optimization.md +0 -274
|
@@ -4,6 +4,7 @@ export const meta = {
|
|
|
4
4
|
phases: [
|
|
5
5
|
{ title: 'Parse', detail: 'Parse Work Breakdown into structured implementation phases' },
|
|
6
6
|
{ title: 'Implementation', detail: 'Dispatch developer agents per US, review, commit' },
|
|
7
|
+
{ title: 'Test', detail: 'Single test run after all phases complete' },
|
|
7
8
|
{ title: 'Remediation', detail: 'Fix OPEN issues from Issues Register' },
|
|
8
9
|
{ title: 'PR', detail: 'Push branch, create PR, update registry' },
|
|
9
10
|
{ title: 'Actuals', detail: 'Write Token-Estimate and Effort-Estimate actuals' },
|
|
@@ -237,6 +238,16 @@ const executePhase = async (implPhase) => {
|
|
|
237
238
|
}
|
|
238
239
|
|
|
239
240
|
phasesDone++
|
|
241
|
+
|
|
242
|
+
// Persist the cumulative token ledger to disk after every completed phase.
|
|
243
|
+
// budget.spent() is an in-memory counter — if the workflow is stopped (manual
|
|
244
|
+
// stop, crash, timeout) before the Actuals phase, all token data would be lost.
|
|
245
|
+
// Writing the full ledger here means the file always reflects real consumption
|
|
246
|
+
// up to the last completed phase, recoverable manually or by a resumed run.
|
|
247
|
+
await agent(
|
|
248
|
+
`Write the following JSON to ${featureDir}/${prefix}-token-ledger.json (overwrite the file if it exists):\n${JSON.stringify(tokenLedger, null, 2)}`,
|
|
249
|
+
{ label: `persist-ledger:${implPhase.phase_id}`, phase: 'Implementation', model: 'haiku' }
|
|
250
|
+
)
|
|
240
251
|
}
|
|
241
252
|
|
|
242
253
|
// Execute waves: phases in the same wave run in parallel, waves are sequential
|
|
@@ -267,6 +278,28 @@ issuesPath = issuesResult?.path || ''
|
|
|
267
278
|
issuesOpen = issuesResult?.open_count || 0
|
|
268
279
|
log(`Implementation complete — ${phasesDone} phases, ${usPassed.length} US passed, ${usEscalated.length} escalated, ${issuesOpen} open issues`)
|
|
269
280
|
|
|
281
|
+
// ── Final test run ────────────────────────────────────────────────────────────
|
|
282
|
+
// Developer agents no longer run the test suite themselves (they do a syntax-check
|
|
283
|
+
// build at most). Running the suite once here, after all files are written, replaces
|
|
284
|
+
// N parallel per-agent test runs — cutting ~1h of duplicated builds and artifact
|
|
285
|
+
// contention down to a single centralized run with one consolidated failure report.
|
|
286
|
+
phase('Test')
|
|
287
|
+
|
|
288
|
+
const beforeTest = budget.spent()
|
|
289
|
+
await agent(
|
|
290
|
+
`Run the full test suite in the repository root and report the result.
|
|
291
|
+
|
|
292
|
+
1. Read AGENTS.md in the repository root to find the exact test command for this project.
|
|
293
|
+
2. Run that command (e.g. \`dotnet test --no-restore --logger "console;verbosity=normal"\`, \`npm test\`).
|
|
294
|
+
3. Report the outcome: total passed/failed, and for any failures the test name and first error line.
|
|
295
|
+
|
|
296
|
+
Do NOT fix failing tests — only report them.`,
|
|
297
|
+
{ label: 'final-test-run', phase: 'Test', model: 'haiku' }
|
|
298
|
+
)
|
|
299
|
+
const testTokens = budget.spent() - beforeTest
|
|
300
|
+
tokenLedger.push({ agent: 'final-test-run', model: 'haiku', phase_delta_tokens: testTokens })
|
|
301
|
+
log(`Test run complete — ${testTokens} tokens`)
|
|
302
|
+
|
|
270
303
|
// ── Remediation ───────────────────────────────────────────────────────────────
|
|
271
304
|
phase('Remediation')
|
|
272
305
|
|
|
@@ -381,8 +414,77 @@ log(`PR done: ${prResult.pr_url} — ${prTokens} tokens`)
|
|
|
381
414
|
// ── Actuals ───────────────────────────────────────────────────────────────────
|
|
382
415
|
phase('Actuals')
|
|
383
416
|
|
|
417
|
+
// Fallback: merge in any ledger entries that were persisted to disk but are missing
|
|
418
|
+
// from the in-memory ledger (e.g. this is a resumed run and earlier phases ran in a
|
|
419
|
+
// previous, interrupted invocation). The in-memory ledger has priority for entries
|
|
420
|
+
// present in both — it reflects the most recent measurements.
|
|
421
|
+
const persistedLedgerRaw = await agent(
|
|
422
|
+
`Read ${featureDir}/${prefix}-token-ledger.json and return its contents as a raw JSON string, nothing else. If the file does not exist, return exactly "[]".`,
|
|
423
|
+
{ label: 'read-ledger', phase: 'Actuals', model: 'haiku' }
|
|
424
|
+
)
|
|
425
|
+
try {
|
|
426
|
+
const persisted = JSON.parse(typeof persistedLedgerRaw === 'string' ? persistedLedgerRaw.trim() : '[]')
|
|
427
|
+
if (Array.isArray(persisted)) {
|
|
428
|
+
const inMemoryByAgent = new Map(tokenLedger.map((e, i) => [e.agent, i]))
|
|
429
|
+
for (const entry of persisted) {
|
|
430
|
+
if (!entry || !entry.agent) continue
|
|
431
|
+
const idx = inMemoryByAgent.get(entry.agent)
|
|
432
|
+
if (idx === undefined) {
|
|
433
|
+
// entry exists on disk but not in memory — recover it (e.g. from a prior interrupted run)
|
|
434
|
+
tokenLedger.push(entry)
|
|
435
|
+
inMemoryByAgent.set(entry.agent, tokenLedger.length - 1)
|
|
436
|
+
log(`Recovered ledger entry from disk: ${entry.agent} (${entry.phase_delta_tokens} tokens)`)
|
|
437
|
+
} else if (tokenLedger[idx].phase_delta_tokens === 0 && (entry.phase_delta_tokens || 0) > 0) {
|
|
438
|
+
// in-memory entry has delta=0 (cached agent on resume) but disk has real data — prefer disk
|
|
439
|
+
tokenLedger[idx] = entry
|
|
440
|
+
log(`Restored real token count from disk: ${entry.agent} (${entry.phase_delta_tokens} tokens)`)
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
} catch (e) {
|
|
445
|
+
log(`Could not parse persisted token ledger — using in-memory ledger only`)
|
|
446
|
+
}
|
|
447
|
+
|
|
384
448
|
const totalPhase3Tokens = tokenLedger.reduce((s, e) => s + (e.phase_delta_tokens || 0), 0)
|
|
385
449
|
|
|
450
|
+
// ── Load token pricing for cost columns ──────────────────────────────────────
|
|
451
|
+
const pricingRaw3 = await agent(
|
|
452
|
+
`Read the file docs/token-pricing.json and return its raw JSON contents as a string, nothing else.`,
|
|
453
|
+
{ label: 'read-pricing', phase: 'Actuals', model: 'haiku' }
|
|
454
|
+
)
|
|
455
|
+
let pricing3 = null
|
|
456
|
+
try { pricing3 = JSON.parse(typeof pricingRaw3 === 'string' ? pricingRaw3.trim() : '{}') } catch (_) {}
|
|
457
|
+
|
|
458
|
+
function tokenCostEur3(tokens, model) {
|
|
459
|
+
if (!pricing3 || !pricing3.models) return null
|
|
460
|
+
const m = pricing3.models[model] || pricing3.models['sonnet']
|
|
461
|
+
const usdPer1M = 0.8 * m.input_per_1m_usd + 0.2 * m.output_per_1m_usd
|
|
462
|
+
return (tokens * usdPer1M / 1_000_000) * (pricing3.usd_to_eur || 1)
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
function formatEur3(val) {
|
|
466
|
+
if (val === null || val === undefined) return '—'
|
|
467
|
+
return '€' + val.toFixed(4)
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// Aggregate the per-agent ledger into per-role totals so the actuals line up with the
|
|
471
|
+
// per-role estimate rows pm-phase2 wrote (developer-backend, developer-testing,
|
|
472
|
+
// review-solution, pr-and-registry, write-actuals, plus final-test-run). Precomputing
|
|
473
|
+
// here keeps the write-actuals agent from having to reason about grouping.
|
|
474
|
+
const roleTotals = {}
|
|
475
|
+
const roleModels = {}
|
|
476
|
+
for (const e of tokenLedger) {
|
|
477
|
+
const role = String(e.agent).split(':')[0]
|
|
478
|
+
roleTotals[role] = (roleTotals[role] || 0) + (e.phase_delta_tokens || 0)
|
|
479
|
+
roleModels[role] = e.model || 'sonnet'
|
|
480
|
+
}
|
|
481
|
+
const roleRows = Object.entries(roleTotals)
|
|
482
|
+
.map(([role, tok]) => `| ${role} | ${tok} | ${formatEur3(tokenCostEur3(tok, roleModels[role]))} |`)
|
|
483
|
+
.join('\n')
|
|
484
|
+
const totalPhase3CostEur = formatEur3(
|
|
485
|
+
Object.entries(roleTotals).reduce((s, [role, tok]) => s + (tokenCostEur3(tok, roleModels[role]) || 0), 0)
|
|
486
|
+
)
|
|
487
|
+
|
|
386
488
|
const ACTUALS_SCHEMA = {
|
|
387
489
|
type: 'object',
|
|
388
490
|
properties: {
|
|
@@ -405,30 +507,50 @@ ${JSON.stringify(tokenLedger, null, 2)}
|
|
|
405
507
|
|
|
406
508
|
Total tokens consumed by pm-phase3 workflow: ${totalPhase3Tokens} (exact, from budget tracking)
|
|
407
509
|
|
|
408
|
-
TASK 1 —
|
|
409
|
-
|
|
510
|
+
TASK 1 — Fill in the Phase 3 actuals in ${prefix}-Token-Estimate.md IN PLACE.
|
|
511
|
+
Read the file in the feature directory first (it was written by pm-phase2 and already contains
|
|
512
|
+
Phase 1/Phase 2 actuals and the Phase 3 estimate table). If it does not exist, create it.
|
|
410
513
|
|
|
411
|
-
|
|
514
|
+
Do NOT append a second Phase 3 table. Instead:
|
|
412
515
|
|
|
413
|
-
|
|
516
|
+
1. Locate the existing "## Phase 3 — Implementation (Estimates)" section. Replace its heading
|
|
517
|
+
with "## Phase 3 — Implementation (Est. vs Actual, by role)" and REPLACE its table with the
|
|
518
|
+
per-role reconciliation below — filling the "Tokens Actual" and "Actual cost €" columns of the
|
|
519
|
+
existing per-role estimate rows (keep the existing Tokens Est. and Est. cost € values; add a Delta column):
|
|
520
|
+
|
|
521
|
+
| Role | Model | Tokens Actual | Actual cost € |
|
|
522
|
+
|------|-------|--------------|--------------|
|
|
523
|
+
${roleRows}
|
|
524
|
+
| **Phase 3 total** | | **${totalPhase3Tokens}** | **${totalPhase3CostEur}** |
|
|
414
525
|
|
|
415
|
-
|
|
526
|
+
Match each existing estimate row (developer-backend, developer-testing, review-solution,
|
|
527
|
+
remediation, pr-and-registry, write-actuals) to the actual role total above by name, write the
|
|
528
|
+
actual into its "Tokens Actual" and "Actual cost €" cells, and compute Delta = Actual − Est (tokens).
|
|
529
|
+
Roles present in the actuals but absent from the estimate rows (e.g. final-test-run) get a new row with Est. = —.
|
|
416
530
|
|
|
417
|
-
|
|
418
|
-
> Per-agent values are exact where each agent ran separately; proportional where merged.
|
|
531
|
+
2. Immediately after that table, add the per-agent detail as a sub-table (source of truth):
|
|
419
532
|
|
|
420
|
-
|
|
421
|
-
|-------|-------|-------|------------|--------------|
|
|
422
|
-
${tokenLedger.map(e => `| ${e.agent} | — | ${e.model} | — | ${e.phase_delta_tokens} |`).join('\n')}
|
|
423
|
-
| **Phase 3 total** | | | **—** | **${totalPhase3Tokens}** |
|
|
533
|
+
### Phase 3 — per-agent detail (actuals)
|
|
424
534
|
|
|
425
|
-
|
|
535
|
+
| Agent | Model | Tokens Actual | Actual cost € |
|
|
536
|
+
|-------|-------|--------------|--------------|
|
|
537
|
+
${tokenLedger.map(e => `| ${e.agent} | ${e.model} | ${e.phase_delta_tokens} | ${formatEur3(tokenCostEur3(e.phase_delta_tokens, e.model))} |`).join('\n')}
|
|
538
|
+
| **Detail total** | | **${totalPhase3Tokens}** | **${totalPhase3CostEur}** |
|
|
426
539
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
540
|
+
3. Update the existing "## Grand Total" table. Read the Phase 1 and Phase 2 actual totals from
|
|
541
|
+
the top of THIS SAME file (the "Phase 1 total" and "Phase 2 total" rows already present) and
|
|
542
|
+
copy them verbatim — never the literal text "(see above)". If a value there is "—" (Phase 1 is
|
|
543
|
+
written as a placeholder by pm-phase2 and filled later by the orchestrator), keep it as "—";
|
|
544
|
+
do NOT invent a number. The table must read:
|
|
545
|
+
|
|
546
|
+
| Phase | Tokens Est. | Est. cost € | Tokens Actual | Actual cost € | Delta (tokens) |
|
|
547
|
+
|-------|------------|------------|--------------|--------------|---------------|
|
|
548
|
+
| Phase 1 — Documentation | — | — | {Phase 1 total from this file, or — if placeholder} | — | — |
|
|
549
|
+
| Phase 2 — Work Breakdown | — | — | {Phase 2 total from this file} | {Phase 2 cost from this file} | — |
|
|
550
|
+
| Phase 3 — Implementation | {existing Phase 3 estimate total} | {existing Phase 3 est. cost} | ${totalPhase3Tokens} | ${totalPhase3CostEur} | {Actual − Est} |
|
|
551
|
+
| **Total** | **{sum of numeric Est}** | **{sum of numeric Est. cost}** | **{sum of numeric Actual}** | **{sum of numeric Actual cost}** | **{Actual − Est}** |
|
|
552
|
+
|
|
553
|
+
4. Append (or update if present) the Implementation Summary section:
|
|
432
554
|
|
|
433
555
|
## Implementation Summary
|
|
434
556
|
|
|
@@ -438,6 +560,8 @@ ${tokenLedger.map(e => `| ${e.agent} | — | ${e.model} | — | ${e.phase_delta_
|
|
|
438
560
|
| US passed | ${usPassed.join(', ') || 'N/A'} |
|
|
439
561
|
| US escalated | ${usEscalated.join(', ') || 'none'} |
|
|
440
562
|
|
|
563
|
+
Remove the stale "*Actuals will be appended by pm-phase3...*" footer line if it is still present.
|
|
564
|
+
|
|
441
565
|
TASK 2 — Update actuals in ${prefix}-Effort-Estimate.md:
|
|
442
566
|
Find the file in the feature directory. Read the existing Per-Phase Breakdown table and update the "Actual Agent" column for each phase that was implemented. Use the token ledger to infer which phases completed:
|
|
443
567
|
- Phases in usPassed: ${usPassed.join(', ') || 'none'} — mark Actual Agent as completed (write the wall-clock duration if available, otherwise write "done (agent)")
|
|
@@ -501,6 +625,17 @@ ${phase3Events}`,
|
|
|
501
625
|
{ label: 'finalize-process-log', phase: 'Actuals' }
|
|
502
626
|
)
|
|
503
627
|
|
|
628
|
+
await agent(
|
|
629
|
+
`Commit the actuals files for this feature delivery run.
|
|
630
|
+
|
|
631
|
+
Run these exact git commands in the repository root:
|
|
632
|
+
git add "${featureDir3}/${prefix}-Token-Estimate.md" "${featureDir3}/${prefix}-Effort-Estimate.md" "${featureDir3}/${prefix}-process-log.txt"
|
|
633
|
+
git commit -m "docs(${prefix}): add token/effort actuals and process log"
|
|
634
|
+
|
|
635
|
+
If there is nothing to commit (all files already committed), that is fine — report success.`,
|
|
636
|
+
{ label: 'commit-actuals', phase: 'Actuals' }
|
|
637
|
+
)
|
|
638
|
+
|
|
504
639
|
return {
|
|
505
640
|
pr_url: prResult.pr_url,
|
|
506
641
|
token_ledger: tokenLedger,
|
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,55 @@
|
|
|
1
1
|
## 0.1.4 (2026-07-21)
|
|
2
|
+
## [0.8.0](https://github.com/dtlab-tech/ai-toolkit/compare/v0.7.0...v0.8.0) (2026-08-04)
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
* **FTR-011:** implement shared infrastructure (INFRA) ([718b0eb](https://github.com/dtlab-tech/ai-toolkit/commit/718b0ebe684814028b0457351a40b171ea80a197))
|
|
8
|
+
* **FTR-011:** implement US-01 — Implement readManifest() Function ([aad7de1](https://github.com/dtlab-tech/ai-toolkit/commit/aad7de19aa6aaf48578c46eebd3bb236ebb4fadb))
|
|
9
|
+
* **FTR-011:** implement US-02 — Implement computeOrphans() Function ([3a70517](https://github.com/dtlab-tech/ai-toolkit/commit/3a705173e649aa7782d036b5790c830c88a1d797))
|
|
10
|
+
* **FTR-011:** implement US-03 — Implement moveToTrash() Function ([a6ac7d2](https://github.com/dtlab-tech/ai-toolkit/commit/a6ac7d2d841905bba24f5349a7d763c9f43527e8))
|
|
11
|
+
* **FTR-011:** implement US-04 — Implement writeManifest() Function ([dc43ea1](https://github.com/dtlab-tech/ai-toolkit/commit/dc43ea1e35c2e4981876ad5f46b3138890851fcd))
|
|
12
|
+
* **FTR-011:** implement US-05 — Integrate Prune Phase into runInstall() and Add UI Display ([bca87ea](https://github.com/dtlab-tech/ai-toolkit/commit/bca87ea8f8843f6a8a07371eaef072b1fc004453))
|
|
13
|
+
* **FTR-011:** implement US-06 — Add CI Safety Net — Agent Name-to-Filename Alignment Check ([06db318](https://github.com/dtlab-tech/ai-toolkit/commit/06db3180b4867b611a2793bf2c74e8510e66827c))
|
|
14
|
+
* **FTR-011:** Installer Manifest and Orphan Pruning ([764eff4](https://github.com/dtlab-tech/ai-toolkit/commit/764eff4dd3b13ee34e7e4be7159c08168e49fe1d))
|
|
15
|
+
* **FTR-011:** update effort and token estimates, add implementation summary, and log completion details ([ce5660d](https://github.com/dtlab-tech/ai-toolkit/commit/ce5660dec691b75bb501bcadb149c2f4eaabdb5a))
|
|
16
|
+
* **FTR-012:** implement shared infrastructure (INFRA) ([da14ae1](https://github.com/dtlab-tech/ai-toolkit/commit/da14ae15d19301c47231e73872ecba75f180e739))
|
|
17
|
+
* **FTR-012:** implement US-01 — Fresh Installation with Allowlist Opt-In ([803018a](https://github.com/dtlab-tech/ai-toolkit/commit/803018aafe77abb06390849540f7fb214fccbc40))
|
|
18
|
+
* **FTR-012:** implement US-02 — Merge Allowlist into Existing Settings ([9855abc](https://github.com/dtlab-tech/ai-toolkit/commit/9855abc940443d4e75b7a1b3340715d8e1403fcf))
|
|
19
|
+
* **FTR-012:** implement US-03 — Ask-Beats-Allow Conflict Resolution ([9c51984](https://github.com/dtlab-tech/ai-toolkit/commit/9c5198490824647bac7b1850b09e624d9f00e883))
|
|
20
|
+
* **FTR-012:** implement US-04 — Reinstall with Idempotent Merge ([8e9a49f](https://github.com/dtlab-tech/ai-toolkit/commit/8e9a49f69d7bb761a698b2ac7f7a405d5d2d833e))
|
|
21
|
+
* **FTR-012:** implement US-05 — .gitignore Creation and Idempotent Update ([20e19de](https://github.com/dtlab-tech/ai-toolkit/commit/20e19de3c38cbbfcd5dd27c8b8b5ab629036b101))
|
|
22
|
+
* **FTR-012:** Installer Bash Allowlist ([2deb73e](https://github.com/dtlab-tech/ai-toolkit/commit/2deb73ef4ad4189c6eea1ae46ec0f0dc6ece469e))
|
|
23
|
+
* **FTR-012:** mark feature as completed in registry ([ab90d58](https://github.com/dtlab-tech/ai-toolkit/commit/ab90d5878a4091ccaef38863c14634ebd2082623))
|
|
24
|
+
* **FTR-013:** add additional agent entries for US-03 and US-04 in ledger ([6f756ed](https://github.com/dtlab-tech/ai-toolkit/commit/6f756edfaa0d75b48809aa3964261efa65fd69f9))
|
|
25
|
+
* **FTR-013:** add registry entry and update ledger actuals ([23f5138](https://github.com/dtlab-tech/ai-toolkit/commit/23f513801486c36e95782ea513e15fcfcb755d06))
|
|
26
|
+
* **FTR-013:** implement shared infrastructure (INFRA) ([99d564f](https://github.com/dtlab-tech/ai-toolkit/commit/99d564f8ca543b7cd95c5cf1a5687961ef402921))
|
|
27
|
+
* **FTR-013:** implement US-01 — Initialize and Track Ledger in define-feature Agent ([ce0b010](https://github.com/dtlab-tech/ai-toolkit/commit/ce0b010afd40e94f9e9e2618eca1fbcc60ede7ae))
|
|
28
|
+
* **FTR-013:** implement US-01 — Initialize and Track Ledger in define-feature Agent ([ca84538](https://github.com/dtlab-tech/ai-toolkit/commit/ca84538d6980828313d331e4a07e10bde5cb34c7))
|
|
29
|
+
* **FTR-013:** implement US-02 — Track Phase 1 Agent Invocations ([a4e3b10](https://github.com/dtlab-tech/ai-toolkit/commit/a4e3b1001bb0b6201c873c4608c23c94c37ca5e0))
|
|
30
|
+
* **FTR-013:** implement US-02 — Track Phase 1 Agent Invocations ([85d86e4](https://github.com/dtlab-tech/ai-toolkit/commit/85d86e406d9ace96b22214de5aef14a6b0cde0b2))
|
|
31
|
+
* **FTR-013:** implement US-03 — Track Phase 2 Agent Invocations ([819f3c3](https://github.com/dtlab-tech/ai-toolkit/commit/819f3c33a954ce89bb221461ee21092b9429c085))
|
|
32
|
+
* **FTR-013:** implement US-03 — Track Phase 2 Agent Invocations ([7d6f9bb](https://github.com/dtlab-tech/ai-toolkit/commit/7d6f9bba8a794e83a12b31a306e27a5d8505c3f7))
|
|
33
|
+
* **FTR-013:** Ledger Pipeline Activity Tracker ([f1bf49a](https://github.com/dtlab-tech/ai-toolkit/commit/f1bf49a4c7496fba8f0c04c5770fe2ad08a6b4ac))
|
|
34
|
+
* **pm:** add EUR cost columns to Token-Estimate ([b0faf0d](https://github.com/dtlab-tech/ai-toolkit/commit/b0faf0dc15c40358bf64b55a0a34987be8db19a2))
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
### Bug Fixes
|
|
38
|
+
|
|
39
|
+
* **FTR-011:** remediate review issues ([c34d824](https://github.com/dtlab-tech/ai-toolkit/commit/c34d8246fff5548401cb50cc300043679ede4bba))
|
|
40
|
+
* **FTR-012:** remediate review issues ([f9ea280](https://github.com/dtlab-tech/ai-toolkit/commit/f9ea280c394a6436fa6a0840f0110b1b620b6025))
|
|
41
|
+
* **pm:** commit actuals after write-actuals; restore zero-delta ledger entries on resume ([83bbaec](https://github.com/dtlab-tech/ai-toolkit/commit/83bbaecdbbbbf9aa436af8d56a6e823500868b1b))
|
|
42
|
+
* **pm:** correct write-actuals token estimate output ([d45653a](https://github.com/dtlab-tech/ai-toolkit/commit/d45653a2c9f999ec8478836e01128428295fa95a))
|
|
43
|
+
|
|
44
|
+
## [0.7.0](https://github.com/dtlab-tech/ai-toolkit/compare/v0.6.0...v0.7.0) (2026-07-29)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
### Features
|
|
48
|
+
|
|
49
|
+
* **pipeline:** centralized test run + persistent token ledger + validation report fix + smarter define-feature ([c9fad6e](https://github.com/dtlab-tech/ai-toolkit/commit/c9fad6e4e5dfe25823df1d6534b4e597baa97001))
|
|
50
|
+
* **pm-phase3:** add centralized test run phase to streamline testing process ([972fac5](https://github.com/dtlab-tech/ai-toolkit/commit/972fac55d0754743859a7d75379a41acd49a890d))
|
|
51
|
+
* **pm-phase3:** persist token ledger to disk after every phase ([b6ad681](https://github.com/dtlab-tech/ai-toolkit/commit/b6ad6814770fae31cda60f25298dab9b2739eeaa))
|
|
52
|
+
|
|
2
53
|
## [0.6.0](https://github.com/dtlab-tech/ai-toolkit/compare/v0.5.0...v0.6.0) (2026-07-29)
|
|
3
54
|
|
|
4
55
|
|