@tech-leads-club/harness-toolkit 0.2.4 → 0.3.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 +22 -26
- package/bin/tlc-build.mjs +93 -0
- package/bin/tlc-cli.ts +110 -66
- package/bin/tlc-exec.mjs +16 -13
- package/dist/compact-before.mjs +66 -8
- package/dist/doctor.mjs +178 -41
- package/dist/help-topic.mjs +0 -0
- package/dist/init-project.mjs +2 -7
- package/dist/install-runtime.mjs +100 -17
- package/dist/lessons-cli.mjs +67 -1
- package/dist/obs-cli.mjs +64 -1
- package/dist/price-lookup.mjs +45 -23
- package/dist/prompt-submit.mjs +66 -8
- package/dist/refresh-model-prices.mjs +7190 -46
- package/dist/response-after.mjs +66 -8
- package/dist/run.mjs +66 -8
- package/dist/session-end.mjs +66 -8
- package/dist/session-start.mjs +66 -8
- package/dist/shim.mjs +66 -3
- package/dist/stop.mjs +66 -8
- package/dist/subagent-start.mjs +66 -8
- package/dist/subagent-stop.mjs +66 -8
- package/dist/support.mjs +64 -1
- package/dist/tlc-cli.mjs +193 -87
- package/dist/tool-after.mjs +111 -31
- package/dist/tool-before.mjs +66 -8
- package/dist/tool-failure.mjs +66 -8
- package/dist/uninstall-runtime.mjs +9 -10
- package/docs/log.md +2 -0
- package/docs/measure.md +35 -31
- package/package.json +4 -4
- package/src/core/core.facade.ts +7 -0
- package/src/core/index.ts +1 -0
- package/src/core/pricing/pricing.freshness.ts +118 -0
- package/src/core/skill/skill.link.ts +14 -3
- package/src/entrypoints/shim.ts +8 -2
- package/src/platform/links.ts +73 -0
- package/src/platform/pricing.ts +139 -31
- package/src/providers/cursor/cursor.wiring.ts +11 -8
- package/tools/doctor.ts +78 -8
- package/tools/init-project.ts +7 -7
- package/tools/install-runtime.ts +89 -6
- package/tools/refresh-model-prices.ts +242 -75
- package/tools/uninstall-runtime.ts +23 -19
- package/bin/tlc-build +0 -80
- package/bin/tlc-exec +0 -10
- package/bin/tlc-exec.cmd +0 -4
- package/model-aliases.json +0 -12
- package/model-prices.cursor.json +0 -410
- package/model-prices.json +0 -1
package/dist/subagent-start.mjs
CHANGED
|
@@ -5273,6 +5273,62 @@ function release(root, provider, session) {
|
|
|
5273
5273
|
deletePresenceRecord(root, provider, session);
|
|
5274
5274
|
}
|
|
5275
5275
|
|
|
5276
|
+
// src/core/pricing/pricing.freshness.ts
|
|
5277
|
+
var DEFAULT_TTL_DAYS = 7;
|
|
5278
|
+
var MS_PER_DAY = 86400000;
|
|
5279
|
+
function freshness(meta, now, ttlDays = DEFAULT_TTL_DAYS) {
|
|
5280
|
+
if (meta === null) {
|
|
5281
|
+
return { state: "absent" };
|
|
5282
|
+
}
|
|
5283
|
+
const stamp = meta.refreshedAt;
|
|
5284
|
+
if (stamp === undefined || Number.isNaN(Date.parse(stamp))) {
|
|
5285
|
+
return { state: "undated" };
|
|
5286
|
+
}
|
|
5287
|
+
const ageMs = now.getTime() - Date.parse(stamp);
|
|
5288
|
+
const ageDays = Math.max(0, ageMs / MS_PER_DAY);
|
|
5289
|
+
return ageDays > ttlDays ? { state: "stale", ageDays, refreshedAt: stamp } : { state: "fresh", ageDays, refreshedAt: stamp };
|
|
5290
|
+
}
|
|
5291
|
+
function shouldRefetch(state) {
|
|
5292
|
+
return state.state === "absent" || state.state === "undated" || state.state === "stale";
|
|
5293
|
+
}
|
|
5294
|
+
function freshnessMessage(state, catalogue) {
|
|
5295
|
+
switch (state.state) {
|
|
5296
|
+
case "absent":
|
|
5297
|
+
return `${catalogue}: not on this machine — run \`tlc harness prices refresh\``;
|
|
5298
|
+
case "undated":
|
|
5299
|
+
return `${catalogue}: present but carries no date — it will be refetched`;
|
|
5300
|
+
case "fresh":
|
|
5301
|
+
return `${catalogue}: ${describeAge(state.ageDays)} old`;
|
|
5302
|
+
default:
|
|
5303
|
+
return `${catalogue}: ${describeAge(state.ageDays)} old — run \`tlc harness prices refresh\``;
|
|
5304
|
+
}
|
|
5305
|
+
}
|
|
5306
|
+
var MIN_RETAINED_RATIO = 0.5;
|
|
5307
|
+
function mayReplace(existingCount, incomingCount, minRatio = MIN_RETAINED_RATIO) {
|
|
5308
|
+
if (incomingCount === 0) {
|
|
5309
|
+
return { replace: false, reason: "parsed no entries at all — the upstream format has changed" };
|
|
5310
|
+
}
|
|
5311
|
+
if (existingCount === 0) {
|
|
5312
|
+
return { replace: true, reason: `first catalogue, ${incomingCount} entries` };
|
|
5313
|
+
}
|
|
5314
|
+
if (incomingCount >= existingCount) {
|
|
5315
|
+
return { replace: true, reason: `${existingCount} → ${incomingCount} entries` };
|
|
5316
|
+
}
|
|
5317
|
+
const retained = incomingCount / existingCount;
|
|
5318
|
+
return retained >= minRatio ? { replace: true, reason: `${existingCount} → ${incomingCount} entries` } : {
|
|
5319
|
+
replace: false,
|
|
5320
|
+
reason: `would drop from ${existingCount} to ${incomingCount} entries, keeping the existing catalogue — the upstream format has probably changed`
|
|
5321
|
+
};
|
|
5322
|
+
}
|
|
5323
|
+
function describeAge(ageDays) {
|
|
5324
|
+
if (ageDays < 1) {
|
|
5325
|
+
const hours = Math.max(1, Math.round(ageDays * 24));
|
|
5326
|
+
return `${hours} hour${hours === 1 ? "" : "s"}`;
|
|
5327
|
+
}
|
|
5328
|
+
const days = Math.round(ageDays);
|
|
5329
|
+
return `${days} day${days === 1 ? "" : "s"}`;
|
|
5330
|
+
}
|
|
5331
|
+
|
|
5276
5332
|
// src/core/release/release.decisions.ts
|
|
5277
5333
|
import { existsSync as existsSync17, readdirSync as readdirSync5, readFileSync as readFileSync19 } from "node:fs";
|
|
5278
5334
|
import { join as join18 } from "node:path";
|
|
@@ -5622,7 +5678,8 @@ function linkHealth(target, runtimeHome2, probe) {
|
|
|
5622
5678
|
if (!probe.exists(resolved)) {
|
|
5623
5679
|
return { state: "dangling", target, resolved };
|
|
5624
5680
|
}
|
|
5625
|
-
const
|
|
5681
|
+
const resolveHome = probe.realpath ?? ((path) => path);
|
|
5682
|
+
const home = resolveHome(runtimeHome2).replace(/\/+$/, "");
|
|
5626
5683
|
return resolved === home || resolved.startsWith(`${home}/`) ? { state: "ok", target, resolved } : { state: "outside-runtime", target, resolved };
|
|
5627
5684
|
}
|
|
5628
5685
|
function linkHealthMessage(health) {
|
|
@@ -6769,6 +6826,12 @@ var coreFacade = {
|
|
|
6769
6826
|
coversHandler,
|
|
6770
6827
|
decideShim
|
|
6771
6828
|
},
|
|
6829
|
+
pricing: {
|
|
6830
|
+
freshness,
|
|
6831
|
+
freshnessMessage,
|
|
6832
|
+
mayReplace,
|
|
6833
|
+
shouldRefetch
|
|
6834
|
+
},
|
|
6772
6835
|
skill: {
|
|
6773
6836
|
linkHealth,
|
|
6774
6837
|
linkHealthMessage,
|
|
@@ -7719,14 +7782,9 @@ var ENTRY_SPECS2 = [
|
|
|
7719
7782
|
{ hookEvent: "stop", handler: "stop", timeoutSeconds: 120, loopLimit: 5 },
|
|
7720
7783
|
{ hookEvent: "afterAgentResponse", handler: "response-after", timeoutSeconds: 5, matcher: "AgentResponse" }
|
|
7721
7784
|
];
|
|
7722
|
-
function commandFor(runtime) {
|
|
7723
|
-
if (process.platform === "win32") {
|
|
7724
|
-
return { command: "cmd", argsPrefix: ["/c", "node", runtime.launcherPath] };
|
|
7725
|
-
}
|
|
7726
|
-
return { command: "node", argsPrefix: [runtime.launcherPath] };
|
|
7727
|
-
}
|
|
7728
7785
|
function cursorWiring(runtime) {
|
|
7729
|
-
const
|
|
7786
|
+
const command = "node";
|
|
7787
|
+
const argsPrefix = [runtime.launcherPath];
|
|
7730
7788
|
const entries = ENTRY_SPECS2.map((spec) => ({
|
|
7731
7789
|
hookEvent: spec.hookEvent,
|
|
7732
7790
|
handler: spec.handler,
|
package/dist/subagent-stop.mjs
CHANGED
|
@@ -5273,6 +5273,62 @@ function release(root, provider, session) {
|
|
|
5273
5273
|
deletePresenceRecord(root, provider, session);
|
|
5274
5274
|
}
|
|
5275
5275
|
|
|
5276
|
+
// src/core/pricing/pricing.freshness.ts
|
|
5277
|
+
var DEFAULT_TTL_DAYS = 7;
|
|
5278
|
+
var MS_PER_DAY = 86400000;
|
|
5279
|
+
function freshness(meta, now, ttlDays = DEFAULT_TTL_DAYS) {
|
|
5280
|
+
if (meta === null) {
|
|
5281
|
+
return { state: "absent" };
|
|
5282
|
+
}
|
|
5283
|
+
const stamp = meta.refreshedAt;
|
|
5284
|
+
if (stamp === undefined || Number.isNaN(Date.parse(stamp))) {
|
|
5285
|
+
return { state: "undated" };
|
|
5286
|
+
}
|
|
5287
|
+
const ageMs = now.getTime() - Date.parse(stamp);
|
|
5288
|
+
const ageDays = Math.max(0, ageMs / MS_PER_DAY);
|
|
5289
|
+
return ageDays > ttlDays ? { state: "stale", ageDays, refreshedAt: stamp } : { state: "fresh", ageDays, refreshedAt: stamp };
|
|
5290
|
+
}
|
|
5291
|
+
function shouldRefetch(state) {
|
|
5292
|
+
return state.state === "absent" || state.state === "undated" || state.state === "stale";
|
|
5293
|
+
}
|
|
5294
|
+
function freshnessMessage(state, catalogue) {
|
|
5295
|
+
switch (state.state) {
|
|
5296
|
+
case "absent":
|
|
5297
|
+
return `${catalogue}: not on this machine — run \`tlc harness prices refresh\``;
|
|
5298
|
+
case "undated":
|
|
5299
|
+
return `${catalogue}: present but carries no date — it will be refetched`;
|
|
5300
|
+
case "fresh":
|
|
5301
|
+
return `${catalogue}: ${describeAge(state.ageDays)} old`;
|
|
5302
|
+
default:
|
|
5303
|
+
return `${catalogue}: ${describeAge(state.ageDays)} old — run \`tlc harness prices refresh\``;
|
|
5304
|
+
}
|
|
5305
|
+
}
|
|
5306
|
+
var MIN_RETAINED_RATIO = 0.5;
|
|
5307
|
+
function mayReplace(existingCount, incomingCount, minRatio = MIN_RETAINED_RATIO) {
|
|
5308
|
+
if (incomingCount === 0) {
|
|
5309
|
+
return { replace: false, reason: "parsed no entries at all — the upstream format has changed" };
|
|
5310
|
+
}
|
|
5311
|
+
if (existingCount === 0) {
|
|
5312
|
+
return { replace: true, reason: `first catalogue, ${incomingCount} entries` };
|
|
5313
|
+
}
|
|
5314
|
+
if (incomingCount >= existingCount) {
|
|
5315
|
+
return { replace: true, reason: `${existingCount} → ${incomingCount} entries` };
|
|
5316
|
+
}
|
|
5317
|
+
const retained = incomingCount / existingCount;
|
|
5318
|
+
return retained >= minRatio ? { replace: true, reason: `${existingCount} → ${incomingCount} entries` } : {
|
|
5319
|
+
replace: false,
|
|
5320
|
+
reason: `would drop from ${existingCount} to ${incomingCount} entries, keeping the existing catalogue — the upstream format has probably changed`
|
|
5321
|
+
};
|
|
5322
|
+
}
|
|
5323
|
+
function describeAge(ageDays) {
|
|
5324
|
+
if (ageDays < 1) {
|
|
5325
|
+
const hours = Math.max(1, Math.round(ageDays * 24));
|
|
5326
|
+
return `${hours} hour${hours === 1 ? "" : "s"}`;
|
|
5327
|
+
}
|
|
5328
|
+
const days = Math.round(ageDays);
|
|
5329
|
+
return `${days} day${days === 1 ? "" : "s"}`;
|
|
5330
|
+
}
|
|
5331
|
+
|
|
5276
5332
|
// src/core/release/release.decisions.ts
|
|
5277
5333
|
import { existsSync as existsSync17, readdirSync as readdirSync5, readFileSync as readFileSync19 } from "node:fs";
|
|
5278
5334
|
import { join as join18 } from "node:path";
|
|
@@ -5622,7 +5678,8 @@ function linkHealth(target, runtimeHome2, probe) {
|
|
|
5622
5678
|
if (!probe.exists(resolved)) {
|
|
5623
5679
|
return { state: "dangling", target, resolved };
|
|
5624
5680
|
}
|
|
5625
|
-
const
|
|
5681
|
+
const resolveHome = probe.realpath ?? ((path) => path);
|
|
5682
|
+
const home = resolveHome(runtimeHome2).replace(/\/+$/, "");
|
|
5626
5683
|
return resolved === home || resolved.startsWith(`${home}/`) ? { state: "ok", target, resolved } : { state: "outside-runtime", target, resolved };
|
|
5627
5684
|
}
|
|
5628
5685
|
function linkHealthMessage(health) {
|
|
@@ -6769,6 +6826,12 @@ var coreFacade = {
|
|
|
6769
6826
|
coversHandler,
|
|
6770
6827
|
decideShim
|
|
6771
6828
|
},
|
|
6829
|
+
pricing: {
|
|
6830
|
+
freshness,
|
|
6831
|
+
freshnessMessage,
|
|
6832
|
+
mayReplace,
|
|
6833
|
+
shouldRefetch
|
|
6834
|
+
},
|
|
6772
6835
|
skill: {
|
|
6773
6836
|
linkHealth,
|
|
6774
6837
|
linkHealthMessage,
|
|
@@ -7719,14 +7782,9 @@ var ENTRY_SPECS2 = [
|
|
|
7719
7782
|
{ hookEvent: "stop", handler: "stop", timeoutSeconds: 120, loopLimit: 5 },
|
|
7720
7783
|
{ hookEvent: "afterAgentResponse", handler: "response-after", timeoutSeconds: 5, matcher: "AgentResponse" }
|
|
7721
7784
|
];
|
|
7722
|
-
function commandFor(runtime) {
|
|
7723
|
-
if (process.platform === "win32") {
|
|
7724
|
-
return { command: "cmd", argsPrefix: ["/c", "node", runtime.launcherPath] };
|
|
7725
|
-
}
|
|
7726
|
-
return { command: "node", argsPrefix: [runtime.launcherPath] };
|
|
7727
|
-
}
|
|
7728
7785
|
function cursorWiring(runtime) {
|
|
7729
|
-
const
|
|
7786
|
+
const command = "node";
|
|
7787
|
+
const argsPrefix = [runtime.launcherPath];
|
|
7730
7788
|
const entries = ENTRY_SPECS2.map((spec) => ({
|
|
7731
7789
|
hookEvent: spec.hookEvent,
|
|
7732
7790
|
handler: spec.handler,
|
package/dist/support.mjs
CHANGED
|
@@ -5259,6 +5259,62 @@ function release(root, provider, session) {
|
|
|
5259
5259
|
deletePresenceRecord(root, provider, session);
|
|
5260
5260
|
}
|
|
5261
5261
|
|
|
5262
|
+
// src/core/pricing/pricing.freshness.ts
|
|
5263
|
+
var DEFAULT_TTL_DAYS = 7;
|
|
5264
|
+
var MS_PER_DAY = 86400000;
|
|
5265
|
+
function freshness(meta, now, ttlDays = DEFAULT_TTL_DAYS) {
|
|
5266
|
+
if (meta === null) {
|
|
5267
|
+
return { state: "absent" };
|
|
5268
|
+
}
|
|
5269
|
+
const stamp = meta.refreshedAt;
|
|
5270
|
+
if (stamp === undefined || Number.isNaN(Date.parse(stamp))) {
|
|
5271
|
+
return { state: "undated" };
|
|
5272
|
+
}
|
|
5273
|
+
const ageMs = now.getTime() - Date.parse(stamp);
|
|
5274
|
+
const ageDays = Math.max(0, ageMs / MS_PER_DAY);
|
|
5275
|
+
return ageDays > ttlDays ? { state: "stale", ageDays, refreshedAt: stamp } : { state: "fresh", ageDays, refreshedAt: stamp };
|
|
5276
|
+
}
|
|
5277
|
+
function shouldRefetch(state) {
|
|
5278
|
+
return state.state === "absent" || state.state === "undated" || state.state === "stale";
|
|
5279
|
+
}
|
|
5280
|
+
function freshnessMessage(state, catalogue) {
|
|
5281
|
+
switch (state.state) {
|
|
5282
|
+
case "absent":
|
|
5283
|
+
return `${catalogue}: not on this machine — run \`tlc harness prices refresh\``;
|
|
5284
|
+
case "undated":
|
|
5285
|
+
return `${catalogue}: present but carries no date — it will be refetched`;
|
|
5286
|
+
case "fresh":
|
|
5287
|
+
return `${catalogue}: ${describeAge(state.ageDays)} old`;
|
|
5288
|
+
default:
|
|
5289
|
+
return `${catalogue}: ${describeAge(state.ageDays)} old — run \`tlc harness prices refresh\``;
|
|
5290
|
+
}
|
|
5291
|
+
}
|
|
5292
|
+
var MIN_RETAINED_RATIO = 0.5;
|
|
5293
|
+
function mayReplace(existingCount, incomingCount, minRatio = MIN_RETAINED_RATIO) {
|
|
5294
|
+
if (incomingCount === 0) {
|
|
5295
|
+
return { replace: false, reason: "parsed no entries at all — the upstream format has changed" };
|
|
5296
|
+
}
|
|
5297
|
+
if (existingCount === 0) {
|
|
5298
|
+
return { replace: true, reason: `first catalogue, ${incomingCount} entries` };
|
|
5299
|
+
}
|
|
5300
|
+
if (incomingCount >= existingCount) {
|
|
5301
|
+
return { replace: true, reason: `${existingCount} → ${incomingCount} entries` };
|
|
5302
|
+
}
|
|
5303
|
+
const retained = incomingCount / existingCount;
|
|
5304
|
+
return retained >= minRatio ? { replace: true, reason: `${existingCount} → ${incomingCount} entries` } : {
|
|
5305
|
+
replace: false,
|
|
5306
|
+
reason: `would drop from ${existingCount} to ${incomingCount} entries, keeping the existing catalogue — the upstream format has probably changed`
|
|
5307
|
+
};
|
|
5308
|
+
}
|
|
5309
|
+
function describeAge(ageDays) {
|
|
5310
|
+
if (ageDays < 1) {
|
|
5311
|
+
const hours = Math.max(1, Math.round(ageDays * 24));
|
|
5312
|
+
return `${hours} hour${hours === 1 ? "" : "s"}`;
|
|
5313
|
+
}
|
|
5314
|
+
const days = Math.round(ageDays);
|
|
5315
|
+
return `${days} day${days === 1 ? "" : "s"}`;
|
|
5316
|
+
}
|
|
5317
|
+
|
|
5262
5318
|
// src/core/release/release.decisions.ts
|
|
5263
5319
|
import { existsSync as existsSync17, readdirSync as readdirSync5, readFileSync as readFileSync19 } from "node:fs";
|
|
5264
5320
|
import { join as join18 } from "node:path";
|
|
@@ -5608,7 +5664,8 @@ function linkHealth(target, runtimeHome2, probe) {
|
|
|
5608
5664
|
if (!probe.exists(resolved)) {
|
|
5609
5665
|
return { state: "dangling", target, resolved };
|
|
5610
5666
|
}
|
|
5611
|
-
const
|
|
5667
|
+
const resolveHome = probe.realpath ?? ((path) => path);
|
|
5668
|
+
const home = resolveHome(runtimeHome2).replace(/\/+$/, "");
|
|
5612
5669
|
return resolved === home || resolved.startsWith(`${home}/`) ? { state: "ok", target, resolved } : { state: "outside-runtime", target, resolved };
|
|
5613
5670
|
}
|
|
5614
5671
|
function linkHealthMessage(health) {
|
|
@@ -6755,6 +6812,12 @@ var coreFacade = {
|
|
|
6755
6812
|
coversHandler,
|
|
6756
6813
|
decideShim
|
|
6757
6814
|
},
|
|
6815
|
+
pricing: {
|
|
6816
|
+
freshness,
|
|
6817
|
+
freshnessMessage,
|
|
6818
|
+
mayReplace,
|
|
6819
|
+
shouldRefetch
|
|
6820
|
+
},
|
|
6758
6821
|
skill: {
|
|
6759
6822
|
linkHealth,
|
|
6760
6823
|
linkHealthMessage,
|