@wrongstack/plugins 0.309.1 → 0.310.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/dist/cost-tracker/index.d.ts +2 -0
- package/dist/cost-tracker.js +24 -9
- package/dist/index.js +23 -12
- package/dist/todo-tracker/index.d.ts +29 -0
- package/dist/todo-tracker.js +2 -4
- package/package.json +5 -4
|
@@ -45,6 +45,8 @@ export interface ModelPricing {
|
|
|
45
45
|
input: number;
|
|
46
46
|
/** Cost per 1M output (completion) tokens in USD. */
|
|
47
47
|
output: number;
|
|
48
|
+
/** Cost per 1M prompt-cache read tokens; input rate is the safe fallback. */
|
|
49
|
+
cacheRead?: number | undefined;
|
|
48
50
|
}
|
|
49
51
|
declare const plugin: Plugin;
|
|
50
52
|
export default plugin;
|
package/dist/cost-tracker.js
CHANGED
|
@@ -12,13 +12,15 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
12
12
|
};
|
|
13
13
|
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
14
14
|
|
|
15
|
+
// src/cost-tracker/index.ts
|
|
16
|
+
import { expectDefined } from "@wrongstack/core/utils";
|
|
17
|
+
|
|
15
18
|
// src/runtime/index.ts
|
|
16
19
|
var runtime_exports = {};
|
|
17
20
|
__reExport(runtime_exports, runtime_star);
|
|
18
21
|
import * as runtime_star from "@wrongstack/plugin-sdk/runtime";
|
|
19
22
|
|
|
20
23
|
// src/cost-tracker/index.ts
|
|
21
|
-
import { expectDefined } from "@wrongstack/core/utils";
|
|
22
24
|
var API_VERSION = "^0.1.10";
|
|
23
25
|
var PRICING = {
|
|
24
26
|
"gpt-4o": { input: 5, output: 15 },
|
|
@@ -48,14 +50,14 @@ function readCostTrackerConfig(raw) {
|
|
|
48
50
|
};
|
|
49
51
|
}
|
|
50
52
|
var modelKeyCache = new runtime_exports.BoundedMap({ max: 256 });
|
|
51
|
-
function estimateCost(model,
|
|
53
|
+
function estimateCost(model, freshTokens, completionTokens, cachedTokens = 0) {
|
|
52
54
|
let key = modelKeyCache.get(model);
|
|
53
55
|
if (!key) {
|
|
54
56
|
key = model.toLowerCase();
|
|
55
57
|
modelKeyCache.set(model, key);
|
|
56
58
|
}
|
|
57
59
|
const pricing = pricingOverrides[key] ?? bundledFromRegistry[key] ?? PRICING[key] ?? DEFAULT_PRICING;
|
|
58
|
-
const inputCost =
|
|
60
|
+
const inputCost = freshTokens / 1e6 * pricing.input + cachedTokens / 1e6 * (pricing.cacheRead ?? pricing.input);
|
|
59
61
|
const outputCost = completionTokens / 1e6 * pricing.output;
|
|
60
62
|
return inputCost + outputCost;
|
|
61
63
|
}
|
|
@@ -89,12 +91,17 @@ var plugin = {
|
|
|
89
91
|
},
|
|
90
92
|
pricingOverrides: {
|
|
91
93
|
type: "object",
|
|
92
|
-
description: "Per-model pricing overrides in USD per 1M tokens.
|
|
94
|
+
description: "Per-model pricing overrides in USD per 1M tokens. Values are { input, output, cacheRead? }.",
|
|
93
95
|
additionalProperties: {
|
|
94
96
|
type: "object",
|
|
95
97
|
properties: {
|
|
96
98
|
input: { type: "number", minimum: 0, description: "Cost per 1M input tokens in USD" },
|
|
97
|
-
output: { type: "number", minimum: 0, description: "Cost per 1M output tokens in USD" }
|
|
99
|
+
output: { type: "number", minimum: 0, description: "Cost per 1M output tokens in USD" },
|
|
100
|
+
cacheRead: {
|
|
101
|
+
type: "number",
|
|
102
|
+
minimum: 0,
|
|
103
|
+
description: "Cost per 1M prompt-cache read tokens in USD"
|
|
104
|
+
}
|
|
98
105
|
},
|
|
99
106
|
required: ["input", "output"],
|
|
100
107
|
additionalProperties: false
|
|
@@ -127,7 +134,12 @@ var plugin = {
|
|
|
127
134
|
const input = v["input"];
|
|
128
135
|
const output = v["output"];
|
|
129
136
|
if (typeof input !== "number" || typeof output !== "number") continue;
|
|
130
|
-
|
|
137
|
+
const cacheRead = v["cacheRead"];
|
|
138
|
+
pricingOverrides[model.toLowerCase()] = {
|
|
139
|
+
input,
|
|
140
|
+
output,
|
|
141
|
+
...typeof cacheRead === "number" ? { cacheRead } : {}
|
|
142
|
+
};
|
|
131
143
|
}
|
|
132
144
|
}
|
|
133
145
|
if (api.modelsRegistry) {
|
|
@@ -142,7 +154,8 @@ var plugin = {
|
|
|
142
154
|
if (cost && typeof cost.input === "number" && typeof cost.output === "number") {
|
|
143
155
|
bundledFromRegistry[modelId.toLowerCase()] = {
|
|
144
156
|
input: cost.input,
|
|
145
|
-
output: cost.output
|
|
157
|
+
output: cost.output,
|
|
158
|
+
...typeof cost.cache_read === "number" ? { cacheRead: cost.cache_read } : {}
|
|
146
159
|
};
|
|
147
160
|
hydrated += 1;
|
|
148
161
|
}
|
|
@@ -169,10 +182,12 @@ var plugin = {
|
|
|
169
182
|
api.onEvent("provider.response", async (payload) => {
|
|
170
183
|
const usage = payload.usage;
|
|
171
184
|
const model = payload.ctx?.model ?? "unknown";
|
|
172
|
-
const
|
|
185
|
+
const cachedTokens = usage.cacheRead ?? 0;
|
|
186
|
+
const freshTokens = (usage.input ?? 0) + (usage.cacheWrite ?? 0);
|
|
187
|
+
const promptTokens = freshTokens + cachedTokens;
|
|
173
188
|
const completionTokens = usage.output ?? 0;
|
|
174
189
|
const totalTokens = promptTokens + completionTokens;
|
|
175
|
-
const costUsd = estimateCost(model,
|
|
190
|
+
const costUsd = estimateCost(model, freshTokens, completionTokens, cachedTokens);
|
|
176
191
|
const record = {
|
|
177
192
|
promptTokens,
|
|
178
193
|
completionTokens,
|
package/dist/index.js
CHANGED
|
@@ -4370,14 +4370,14 @@ function readCostTrackerConfig(raw) {
|
|
|
4370
4370
|
};
|
|
4371
4371
|
}
|
|
4372
4372
|
var modelKeyCache = new runtime_exports.BoundedMap({ max: 256 });
|
|
4373
|
-
function estimateCost(model,
|
|
4373
|
+
function estimateCost(model, freshTokens, completionTokens, cachedTokens = 0) {
|
|
4374
4374
|
let key = modelKeyCache.get(model);
|
|
4375
4375
|
if (!key) {
|
|
4376
4376
|
key = model.toLowerCase();
|
|
4377
4377
|
modelKeyCache.set(model, key);
|
|
4378
4378
|
}
|
|
4379
4379
|
const pricing = pricingOverrides[key] ?? bundledFromRegistry[key] ?? PRICING[key] ?? DEFAULT_PRICING;
|
|
4380
|
-
const inputCost =
|
|
4380
|
+
const inputCost = freshTokens / 1e6 * pricing.input + cachedTokens / 1e6 * (pricing.cacheRead ?? pricing.input);
|
|
4381
4381
|
const outputCost = completionTokens / 1e6 * pricing.output;
|
|
4382
4382
|
return inputCost + outputCost;
|
|
4383
4383
|
}
|
|
@@ -4411,12 +4411,17 @@ var plugin14 = {
|
|
|
4411
4411
|
},
|
|
4412
4412
|
pricingOverrides: {
|
|
4413
4413
|
type: "object",
|
|
4414
|
-
description: "Per-model pricing overrides in USD per 1M tokens.
|
|
4414
|
+
description: "Per-model pricing overrides in USD per 1M tokens. Values are { input, output, cacheRead? }.",
|
|
4415
4415
|
additionalProperties: {
|
|
4416
4416
|
type: "object",
|
|
4417
4417
|
properties: {
|
|
4418
4418
|
input: { type: "number", minimum: 0, description: "Cost per 1M input tokens in USD" },
|
|
4419
|
-
output: { type: "number", minimum: 0, description: "Cost per 1M output tokens in USD" }
|
|
4419
|
+
output: { type: "number", minimum: 0, description: "Cost per 1M output tokens in USD" },
|
|
4420
|
+
cacheRead: {
|
|
4421
|
+
type: "number",
|
|
4422
|
+
minimum: 0,
|
|
4423
|
+
description: "Cost per 1M prompt-cache read tokens in USD"
|
|
4424
|
+
}
|
|
4420
4425
|
},
|
|
4421
4426
|
required: ["input", "output"],
|
|
4422
4427
|
additionalProperties: false
|
|
@@ -4449,7 +4454,12 @@ var plugin14 = {
|
|
|
4449
4454
|
const input = v["input"];
|
|
4450
4455
|
const output = v["output"];
|
|
4451
4456
|
if (typeof input !== "number" || typeof output !== "number") continue;
|
|
4452
|
-
|
|
4457
|
+
const cacheRead = v["cacheRead"];
|
|
4458
|
+
pricingOverrides[model.toLowerCase()] = {
|
|
4459
|
+
input,
|
|
4460
|
+
output,
|
|
4461
|
+
...typeof cacheRead === "number" ? { cacheRead } : {}
|
|
4462
|
+
};
|
|
4453
4463
|
}
|
|
4454
4464
|
}
|
|
4455
4465
|
if (api.modelsRegistry) {
|
|
@@ -4464,7 +4474,8 @@ var plugin14 = {
|
|
|
4464
4474
|
if (cost && typeof cost.input === "number" && typeof cost.output === "number") {
|
|
4465
4475
|
bundledFromRegistry[modelId.toLowerCase()] = {
|
|
4466
4476
|
input: cost.input,
|
|
4467
|
-
output: cost.output
|
|
4477
|
+
output: cost.output,
|
|
4478
|
+
...typeof cost.cache_read === "number" ? { cacheRead: cost.cache_read } : {}
|
|
4468
4479
|
};
|
|
4469
4480
|
hydrated += 1;
|
|
4470
4481
|
}
|
|
@@ -4491,10 +4502,12 @@ var plugin14 = {
|
|
|
4491
4502
|
api.onEvent("provider.response", async (payload) => {
|
|
4492
4503
|
const usage = payload.usage;
|
|
4493
4504
|
const model = payload.ctx?.model ?? "unknown";
|
|
4494
|
-
const
|
|
4505
|
+
const cachedTokens = usage.cacheRead ?? 0;
|
|
4506
|
+
const freshTokens = (usage.input ?? 0) + (usage.cacheWrite ?? 0);
|
|
4507
|
+
const promptTokens = freshTokens + cachedTokens;
|
|
4495
4508
|
const completionTokens = usage.output ?? 0;
|
|
4496
4509
|
const totalTokens = promptTokens + completionTokens;
|
|
4497
|
-
const costUsd = estimateCost(model,
|
|
4510
|
+
const costUsd = estimateCost(model, freshTokens, completionTokens, cachedTokens);
|
|
4498
4511
|
const record = {
|
|
4499
4512
|
promptTokens,
|
|
4500
4513
|
completionTokens,
|
|
@@ -22673,9 +22686,10 @@ var plugin60 = {
|
|
|
22673
22686
|
var todo_listener_default = plugin60;
|
|
22674
22687
|
|
|
22675
22688
|
// src/todo-tracker/index.ts
|
|
22676
|
-
import * as fsp from "node:fs/promises";
|
|
22677
22689
|
import { randomUUID } from "node:crypto";
|
|
22690
|
+
import * as fsp from "node:fs/promises";
|
|
22678
22691
|
import { atomicWrite as atomicWrite3, ensureDir as ensureDir3 } from "@wrongstack/core/utils";
|
|
22692
|
+
import { nowIso } from "@wrongstack/primitives";
|
|
22679
22693
|
function deriveFilePath(api) {
|
|
22680
22694
|
const raw = api.config.extensions?.["todo-tracker"];
|
|
22681
22695
|
const explicit = typeof raw?.["filePath"] === "string" ? raw["filePath"] : null;
|
|
@@ -22720,9 +22734,6 @@ var state56 = {
|
|
|
22720
22734
|
/** Most recent mutation for /diag plugins visibility. */
|
|
22721
22735
|
lastMutation: null
|
|
22722
22736
|
};
|
|
22723
|
-
function nowIso() {
|
|
22724
|
-
return (/* @__PURE__ */ new Date()).toISOString();
|
|
22725
|
-
}
|
|
22726
22737
|
function ensureFile() {
|
|
22727
22738
|
if (!state56.file) {
|
|
22728
22739
|
state56.file = {
|
|
@@ -1,3 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* todo-tracker plugin — Persistent, project-scoped todo backlog that
|
|
3
|
+
* survives across sessions.
|
|
4
|
+
*
|
|
5
|
+
* Why a separate plugin from the built-in `todo` tool?
|
|
6
|
+
* - The built-in `todo` tool mutates `ctx.todos`, which is
|
|
7
|
+
* session-scoped and auto-clears when all items complete.
|
|
8
|
+
* - todo-tracker writes to disk (`~/.wrongstack/projects/<slug>/todo-tracker.json`)
|
|
9
|
+
* and survives across sessions. Items are explicit add/complete;
|
|
10
|
+
* no auto-clear.
|
|
11
|
+
*
|
|
12
|
+
* Use cases:
|
|
13
|
+
* - Backlog of work the user wants to track over days/weeks
|
|
14
|
+
* - Items the LLM noticed but didn't finish — pull them into a fresh
|
|
15
|
+
* session via `todo_tracker_pull` (the LLM then registers them with
|
|
16
|
+
* the session's `ctx.todos` via the built-in `todo` tool)
|
|
17
|
+
* - Per-project scratchpad that survives `wstack resume <id>`
|
|
18
|
+
*
|
|
19
|
+
* Tools registered:
|
|
20
|
+
* - todo_tracker_list : List items, filterable by status/tag/priority
|
|
21
|
+
* - todo_tracker_add : Append a new item
|
|
22
|
+
* - todo_tracker_complete : Mark an item completed (idempotent)
|
|
23
|
+
* - todo_tracker_drop : Mark an item dropped (idempotent)
|
|
24
|
+
* - todo_tracker_remove : Permanently delete by id
|
|
25
|
+
* - todo_tracker_pull : Return pending items for LLM to promote
|
|
26
|
+
* into the session's ctx.todos via the
|
|
27
|
+
* built-in `todo` tool
|
|
28
|
+
* - todo_tracker_status : Counters + last update timestamp
|
|
29
|
+
*/
|
|
1
30
|
import type { Plugin } from '@wrongstack/core/types';
|
|
2
31
|
declare const plugin: Plugin;
|
|
3
32
|
export default plugin;
|
package/dist/todo-tracker.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// src/todo-tracker/index.ts
|
|
2
|
-
import * as fsp from "node:fs/promises";
|
|
3
2
|
import { randomUUID } from "node:crypto";
|
|
3
|
+
import * as fsp from "node:fs/promises";
|
|
4
4
|
import { atomicWrite, ensureDir } from "@wrongstack/core/utils";
|
|
5
|
+
import { nowIso } from "@wrongstack/primitives";
|
|
5
6
|
function deriveFilePath(api) {
|
|
6
7
|
const raw = api.config.extensions?.["todo-tracker"];
|
|
7
8
|
const explicit = typeof raw?.["filePath"] === "string" ? raw["filePath"] : null;
|
|
@@ -46,9 +47,6 @@ var state = {
|
|
|
46
47
|
/** Most recent mutation for /diag plugins visibility. */
|
|
47
48
|
lastMutation: null
|
|
48
49
|
};
|
|
49
|
-
function nowIso() {
|
|
50
|
-
return (/* @__PURE__ */ new Date()).toISOString();
|
|
51
|
-
}
|
|
52
50
|
function ensureFile() {
|
|
53
51
|
if (!state.file) {
|
|
54
52
|
state.file = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrongstack/plugins",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.310.0",
|
|
4
4
|
"description": "Official WrongStack collection of focused plugins for code quality, security, observability, planning, and agent coordination",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "ECOSTACK TECHNOLOGY OÜ",
|
|
@@ -303,9 +303,10 @@
|
|
|
303
303
|
"vitest": "^4.1.11"
|
|
304
304
|
},
|
|
305
305
|
"dependencies": {
|
|
306
|
-
"@wrongstack/
|
|
307
|
-
"@wrongstack/
|
|
308
|
-
"@wrongstack/
|
|
306
|
+
"@wrongstack/core": "0.310.0",
|
|
307
|
+
"@wrongstack/tools": "0.310.0",
|
|
308
|
+
"@wrongstack/primitives": "0.310.0",
|
|
309
|
+
"@wrongstack/plugin-sdk": "0.310.0"
|
|
309
310
|
},
|
|
310
311
|
"scripts": {
|
|
311
312
|
"build": "node ../../scripts/build-package.mjs",
|