@tech-leads-club/harness-toolkit 0.3.0 → 0.3.2

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.
Files changed (44) hide show
  1. package/README.md +46 -11
  2. package/bin/tlc-build.mjs +35 -6
  3. package/config.example.json +1 -1
  4. package/dist/chunks/compact-before-1e4qg1qt.mjs +1185 -0
  5. package/dist/chunks/compact-before-2hpbfxm5.mjs +5782 -0
  6. package/dist/chunks/compact-before-49j320yp.mjs +1283 -0
  7. package/dist/chunks/compact-before-4jrq0sqs.mjs +61 -0
  8. package/dist/chunks/compact-before-6w8n1vh1.mjs +186 -0
  9. package/dist/chunks/compact-before-7sdmwswh.mjs +52 -0
  10. package/dist/chunks/compact-before-beqpmqrm.mjs +187 -0
  11. package/dist/chunks/compact-before-j9y4jgn4.mjs +845 -0
  12. package/dist/chunks/compact-before-pk86tqx2.mjs +118 -0
  13. package/dist/chunks/compact-before-pkqk5v29.mjs +137 -0
  14. package/dist/chunks/compact-before-w1293m4n.mjs +315 -0
  15. package/dist/chunks/compact-before-wnnds45y.mjs +26 -0
  16. package/dist/chunks/compact-before-wt2c3nh4.mjs +551 -0
  17. package/dist/compact-before.mjs +13 -7961
  18. package/dist/doctor.mjs +33 -8480
  19. package/dist/help-topic.mjs +6 -14
  20. package/dist/init-project.mjs +36 -793
  21. package/dist/install-runtime.mjs +18 -1039
  22. package/dist/lessons-cli.mjs +25 -7043
  23. package/dist/obs-cli.mjs +27 -7037
  24. package/dist/price-lookup.mjs +11 -201
  25. package/dist/prompt-submit.mjs +14 -7974
  26. package/dist/refresh-model-prices.mjs +26 -7061
  27. package/dist/response-after.mjs +11 -7961
  28. package/dist/run.mjs +10 -7960
  29. package/dist/session-end.mjs +14 -8029
  30. package/dist/session-start.mjs +20 -8075
  31. package/dist/shim.mjs +18 -7024
  32. package/dist/stop.mjs +29 -8042
  33. package/dist/subagent-start.mjs +13 -7983
  34. package/dist/subagent-stop.mjs +11 -7961
  35. package/dist/support.mjs +21 -7168
  36. package/dist/tlc-cli.mjs +65 -8200
  37. package/dist/tool-after.mjs +20 -8176
  38. package/dist/tool-before.mjs +15 -7990
  39. package/dist/tool-failure.mjs +14 -7961
  40. package/dist/uninstall-runtime.mjs +61 -1008
  41. package/docs/log.md +4 -0
  42. package/package.json +2 -2
  43. package/src/core/release/release.version.ts +10 -4
  44. package/tools/install-runtime.ts +21 -1
@@ -0,0 +1,61 @@
1
+ import { createRequire } from "node:module";
2
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
3
+
4
+ // src/platform/paths.ts
5
+ import { homedir } from "node:os";
6
+ import { join } from "node:path";
7
+ function harnessDir(root) {
8
+ return join(root, ".tlc", "harness");
9
+ }
10
+ function conventionalRuntimeHome() {
11
+ return join(homedir(), ".tlc", "harness");
12
+ }
13
+ function runtimeHome(env = process.env) {
14
+ return env.TLC_HOME ?? conventionalRuntimeHome();
15
+ }
16
+ function runtimeHomeWasChosen(env = process.env) {
17
+ return env.TLC_HOME_FROM_ENV === "1";
18
+ }
19
+ function runtimeStateDir() {
20
+ return join(runtimeHome(), "state");
21
+ }
22
+ function runtimeSpoolPath() {
23
+ return join(runtimeStateDir(), "obs-spool.jsonl");
24
+ }
25
+ function projectConfigPath(root) {
26
+ return join(harnessDir(root), "config.json");
27
+ }
28
+ function projectStateDir(root) {
29
+ return join(harnessDir(root), "state");
30
+ }
31
+ function flagsDir(root) {
32
+ return join(projectStateDir(root), "flags");
33
+ }
34
+ function presenceDir(root) {
35
+ return join(projectStateDir(root), "presence");
36
+ }
37
+ function loopsDir(root) {
38
+ return join(projectStateDir(root), "loops");
39
+ }
40
+ function bootDir(root) {
41
+ return join(projectStateDir(root), "boot");
42
+ }
43
+ function policyBaselineDir(root) {
44
+ return join(projectStateDir(root), "policy-baseline");
45
+ }
46
+ function claudeConfigDir() {
47
+ const custom = process.env.CLAUDE_CONFIG_DIR?.trim();
48
+ return custom && custom.length > 0 ? custom : join(homedir(), ".claude");
49
+ }
50
+ function cursorConfigDir() {
51
+ const custom = process.env.CURSOR_CONFIG_DIR?.trim();
52
+ return custom && custom.length > 0 ? custom : join(homedir(), ".cursor");
53
+ }
54
+ function userSettingsPaths() {
55
+ return [join(claudeConfigDir(), "settings.json"), join(cursorConfigDir(), "hooks.json")];
56
+ }
57
+ function providerConfigDirs() {
58
+ return [cursorConfigDir(), claudeConfigDir()];
59
+ }
60
+
61
+ export { __require, conventionalRuntimeHome, runtimeHome, runtimeHomeWasChosen, runtimeStateDir, runtimeSpoolPath, projectConfigPath, projectStateDir, flagsDir, presenceDir, loopsDir, bootDir, policyBaselineDir, claudeConfigDir, cursorConfigDir, userSettingsPaths, providerConfigDirs };
@@ -0,0 +1,186 @@
1
+ import {
2
+ NPM_MARKER,
3
+ NPM_PACKAGE,
4
+ linkDir,
5
+ wireRuntime
6
+ } from "./compact-before-1e4qg1qt.mjs";
7
+ import {
8
+ PLAIN,
9
+ createStyle,
10
+ render
11
+ } from "./compact-before-49j320yp.mjs";
12
+ import {
13
+ __require,
14
+ conventionalRuntimeHome,
15
+ runtimeHome,
16
+ runtimeHomeWasChosen
17
+ } from "./compact-before-4jrq0sqs.mjs";
18
+
19
+ // tools/install-runtime.ts
20
+ import { spawnSync } from "node:child_process";
21
+ import { cpSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
22
+ import { join, relative, resolve, sep } from "node:path";
23
+ var RUNTIME_PAYLOAD = [
24
+ "bin",
25
+ "capabilities",
26
+ "dist",
27
+ "docs",
28
+ "skills",
29
+ "src",
30
+ "tools",
31
+ "config.example.json",
32
+ "package.json"
33
+ ];
34
+ var OPERATOR_OWNED = ["config.json", "state", "flags"];
35
+ var NOT_SHIPPED = [join("tools", "dev"), join("tools", "__test__")];
36
+ function isShipped(relativePath) {
37
+ const normalised = relativePath.split(sep).join("/");
38
+ return !NOT_SHIPPED.some((excluded) => {
39
+ const prefix = excluded.split(sep).join("/");
40
+ return normalised === prefix || normalised.startsWith(`${prefix}/`);
41
+ });
42
+ }
43
+ function originRoot(env = process.env) {
44
+ const declared = env.TLC_ORIGIN?.trim();
45
+ if (declared && declared.length > 0) {
46
+ return resolve(declared);
47
+ }
48
+ const home = env.TLC_HOME?.trim();
49
+ return home && home.length > 0 ? resolve(home) : conventionalRuntimeHome();
50
+ }
51
+ function installRuntime(source, dest) {
52
+ if (resolve(source) === resolve(dest)) {
53
+ return { kind: "in-place", source, dest, entries: [], missing: [] };
54
+ }
55
+ mkdirSync(dest, { recursive: true });
56
+ const entries = [];
57
+ const missing = [];
58
+ for (const entry of RUNTIME_PAYLOAD) {
59
+ const from = join(source, entry);
60
+ if (!existsSync(from)) {
61
+ missing.push(entry);
62
+ continue;
63
+ }
64
+ const to = join(dest, entry);
65
+ rmSync(to, { recursive: true, force: true });
66
+ cpSync(from, to, {
67
+ recursive: true,
68
+ filter: (src) => isShipped(relative(source, src))
69
+ });
70
+ entries.push(entry);
71
+ }
72
+ writeFileSync(join(dest, NPM_MARKER), `Installed by \`tlc harness install\` from ${source}.
73
+ Update with: npm i -g ${NPM_PACKAGE}@latest && tlc harness install
74
+ `, "utf8");
75
+ const config = join(dest, "config.json");
76
+ const example = join(dest, "config.example.json");
77
+ if (!existsSync(config) && existsSync(example)) {
78
+ writeFileSync(config, readFileSync(example, "utf8"), "utf8");
79
+ }
80
+ return { kind: "copied", source, dest, entries, missing };
81
+ }
82
+ function linkRuntime(source, dest) {
83
+ if (resolve(source) === resolve(dest)) {
84
+ return { kind: "in-place", source, dest, entries: [], missing: [] };
85
+ }
86
+ const outcome = linkDir(resolve(source), dest);
87
+ if (outcome.kind === "refused") {
88
+ return { kind: "refused", source, dest, entries: [], missing: [], reason: outcome.reason };
89
+ }
90
+ const missing = RUNTIME_PAYLOAD.filter((entry) => !existsSync(join(dest, entry)));
91
+ return { kind: outcome.kind === "relinked" ? "relinked" : "linked", source, dest, entries: [], missing };
92
+ }
93
+ function installScreen(report) {
94
+ if (report.kind === "refused") {
95
+ return {
96
+ title: "harness install",
97
+ sections: [{ rows: [{ label: "refused", value: report.reason ?? "", level: "fail" }] }]
98
+ };
99
+ }
100
+ if (report.kind === "linked" || report.kind === "relinked") {
101
+ return {
102
+ title: "harness install",
103
+ sections: [
104
+ {
105
+ rows: [
106
+ {
107
+ label: report.kind === "linked" ? "linked" : "relinked",
108
+ value: `${report.dest} → ${report.source}`,
109
+ level: "ok"
110
+ },
111
+ ...report.missing.length > 0 ? [
112
+ {
113
+ label: "incomplete",
114
+ value: `the checkout has no ${report.missing.join(", ")} — run the build`,
115
+ level: "fail"
116
+ }
117
+ ] : []
118
+ ]
119
+ }
120
+ ],
121
+ footer: "an edit in the checkout is live in the next hook · `npm link` puts `tlc` on PATH"
122
+ };
123
+ }
124
+ if (report.kind === "in-place") {
125
+ return {
126
+ title: "harness install",
127
+ sections: [
128
+ { rows: [{ label: "runtime", value: `already at ${report.dest} — nothing to copy`, level: "ok" }] }
129
+ ]
130
+ };
131
+ }
132
+ const rows = [
133
+ { label: "installed", value: `${report.entries.length} path(s) → ${report.dest}`, level: "ok" },
134
+ { label: "from", value: report.source }
135
+ ];
136
+ if (report.missing.length > 0) {
137
+ rows.push({
138
+ label: "packaging",
139
+ value: `MISSING from the source: ${report.missing.join(", ")}`,
140
+ level: "fail"
141
+ });
142
+ }
143
+ return { title: "harness install", sections: [{ rows }] };
144
+ }
145
+ function installReportText(report, style = PLAIN) {
146
+ return render(installScreen(report), style);
147
+ }
148
+ function installDest(env = process.env) {
149
+ const explicit = env.TLC_INSTALL_DEST?.trim();
150
+ if (explicit && explicit.length > 0) {
151
+ return resolve(explicit);
152
+ }
153
+ return runtimeHomeWasChosen(env) ? runtimeHome(env) : conventionalRuntimeHome();
154
+ }
155
+ function fetchPrices(dest, spawn = spawnSync) {
156
+ const result = spawn(process.execPath, [join(dest, "bin", "tlc-exec.mjs"), "refresh-model-prices"], {
157
+ stdio: "inherit",
158
+ env: { ...process.env, TLC_HOME: dest }
159
+ });
160
+ if ((result.status ?? 1) !== 0) {
161
+ console.log("install: prices not fetched — cost estimates stay empty until `tlc harness prices refresh`");
162
+ }
163
+ }
164
+ if (__require.main == __require.module) {
165
+ const link = process.argv.includes("--link");
166
+ const source = link ? process.cwd() : originRoot();
167
+ const dest = installDest();
168
+ const report = link ? linkRuntime(source, dest) : installRuntime(source, dest);
169
+ console.log(installReportText(report, createStyle()));
170
+ if (report.kind === "refused") {
171
+ process.exit(1);
172
+ }
173
+ const wired = wireRuntime(dest, dest);
174
+ for (const line of wired.lines) {
175
+ console.log(`install: ${line}`);
176
+ }
177
+ if (wired.missingSkill) {
178
+ console.error(`install: missing skill at ${join(dest, "skills", "harness-init")}`);
179
+ process.exit(1);
180
+ }
181
+ fetchPrices(dest);
182
+ console.log("install: ok — restart Cursor or Claude Code, then run `tlc harness doctor`");
183
+ process.exit(report.missing.length > 0 ? 1 : 0);
184
+ }
185
+
186
+ export { RUNTIME_PAYLOAD, OPERATOR_OWNED, NOT_SHIPPED, isShipped, originRoot, installRuntime, linkRuntime, installScreen, installReportText, installDest, fetchPrices };
@@ -0,0 +1,52 @@
1
+ // bin/write-user-hooks.mjs
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ var CURSOR_MARKER = "tlc-exec.mjs";
5
+ function quoteIfNeeded(token) {
6
+ return token.includes(" ") ? `"${token}"` : token;
7
+ }
8
+ function commandStringFor(entry) {
9
+ return [entry.command, ...entry.args].map(quoteIfNeeded).join(" ");
10
+ }
11
+ function renderCursorHooksDocument(entries) {
12
+ const hooks = {};
13
+ for (const entry of entries) {
14
+ const rendered = { command: commandStringFor(entry), timeout: entry.timeoutSeconds };
15
+ if (entry.failClosed) {
16
+ rendered.failClosed = true;
17
+ }
18
+ if (entry.matcher !== undefined) {
19
+ rendered.matcher = entry.matcher;
20
+ }
21
+ if (entry.loopLimit !== undefined) {
22
+ rendered.loop_limit = entry.loopLimit;
23
+ }
24
+ hooks[entry.hookEvent] = [...hooks[entry.hookEvent] ?? [], rendered];
25
+ }
26
+ return { version: 1, hooks };
27
+ }
28
+ function isCursorWired(targetPath) {
29
+ return existsSync(targetPath) && readFileSync(targetPath, "utf8").includes(CURSOR_MARKER);
30
+ }
31
+ function applyCursorWiring(wiring, { force = false } = {}) {
32
+ const targetPath = wiring.target;
33
+ const document = renderCursorHooksDocument(wiring.entries);
34
+ const rendered = `${JSON.stringify(document, null, 2)}
35
+ `;
36
+ if (existsSync(targetPath) && !force) {
37
+ if (isCursorWired(targetPath)) {
38
+ return { status: "unchanged", target: targetPath };
39
+ }
40
+ return {
41
+ status: "refused",
42
+ target: targetPath,
43
+ reason: `${targetPath} exists without harness entries — rerun with --force to overwrite, or merge manually.`
44
+ };
45
+ }
46
+ mkdirSync(dirname(targetPath), { recursive: true });
47
+ writeFileSync(targetPath, rendered);
48
+ return { status: "written", target: targetPath };
49
+ }
50
+ if (false) {}
51
+
52
+ export { renderCursorHooksDocument, isCursorWired, applyCursorWiring };
@@ -0,0 +1,187 @@
1
+ import {
2
+ runtimeHome
3
+ } from "./compact-before-4jrq0sqs.mjs";
4
+
5
+ // src/platform/pricing.ts
6
+ import { existsSync, readFileSync } from "node:fs";
7
+ import { join } from "node:path";
8
+ var FALLBACK_PLANE = "litellm";
9
+ var MODEL_ALIASES = {
10
+ "cursor-grok-4.5": "grok-4.5",
11
+ auto: "auto-cost"
12
+ };
13
+ var VENDOR_TO_NEUTRAL_POOL = {
14
+ cursor_models: "provider_native",
15
+ anthropic_models: "provider_native",
16
+ other_models: "other",
17
+ auto: "auto",
18
+ unknown: "unknown"
19
+ };
20
+ function mapPoolToNeutral(pool) {
21
+ return VENDOR_TO_NEUTRAL_POOL[pool];
22
+ }
23
+ function stripMeta(table) {
24
+ if (!table) {
25
+ return {};
26
+ }
27
+ const { _meta: _ignored, ...rest } = table;
28
+ return rest;
29
+ }
30
+ function slugifyModelName(name) {
31
+ return name.trim().toLowerCase().replace(/\[([^\]]+)\]\([^)]*\)/g, "$1").replace(/[[\]]/g, "").replace(/[^a-z0-9.+]+/g, "-").replace(/^-+|-+$/g, "");
32
+ }
33
+ function candidatesFor(model, aliases) {
34
+ const trimmed = model.trim();
35
+ const out = [];
36
+ const push = (v) => {
37
+ if (v && !out.includes(v)) {
38
+ out.push(v);
39
+ }
40
+ };
41
+ push(trimmed);
42
+ push(aliases[trimmed]);
43
+ push(slugifyModelName(trimmed));
44
+ push(aliases[slugifyModelName(trimmed)]);
45
+ if (trimmed.includes("/")) {
46
+ push(trimmed.slice(trimmed.lastIndexOf("/") + 1));
47
+ }
48
+ const noEffort = trimmed.replace(/-(high|medium|low|max|fast|thinking)$/i, "");
49
+ if (noEffort !== trimmed) {
50
+ push(noEffort);
51
+ push(aliases[noEffort]);
52
+ push(slugifyModelName(noEffort));
53
+ }
54
+ return out;
55
+ }
56
+ function fuzzyFind(table, needle) {
57
+ const direct = table[needle];
58
+ if (direct) {
59
+ return { key: needle, entry: direct };
60
+ }
61
+ for (const [key, entry] of Object.entries(table)) {
62
+ if (needle.startsWith(key) || key.startsWith(needle)) {
63
+ return { key, entry };
64
+ }
65
+ }
66
+ return;
67
+ }
68
+ function cataloguePath() {
69
+ return join(runtimeHome(), "model-prices.json");
70
+ }
71
+ function overridesPath() {
72
+ return join(runtimeHome(), "model-prices.local.json");
73
+ }
74
+ var cache = new Map;
75
+ function readCatalogue(path) {
76
+ if (!existsSync(path)) {
77
+ cache.delete(path);
78
+ return null;
79
+ }
80
+ let text;
81
+ try {
82
+ text = readFileSync(path, "utf8");
83
+ } catch {
84
+ cache.delete(path);
85
+ return null;
86
+ }
87
+ const hit = cache.get(path);
88
+ if (hit && hit.text === text) {
89
+ return hit.value;
90
+ }
91
+ let parsed;
92
+ try {
93
+ parsed = JSON.parse(text);
94
+ } catch {
95
+ cache.delete(path);
96
+ return null;
97
+ }
98
+ cache.set(path, { text, value: parsed });
99
+ return parsed;
100
+ }
101
+ function loadCatalogue() {
102
+ return readCatalogue(cataloguePath()) ?? {};
103
+ }
104
+ function planeMeta() {
105
+ return loadCatalogue()._meta?.planes ?? {};
106
+ }
107
+ function catalogueMeta() {
108
+ const parsed = readCatalogue(cataloguePath());
109
+ return parsed === null ? null : parsed._meta ?? {};
110
+ }
111
+ function planeFor(catalogue, plane) {
112
+ return stripMeta(catalogue.planes?.[plane] ?? null);
113
+ }
114
+ function resolveModelPrice(provider, model) {
115
+ const trimmed = model.trim();
116
+ if (!trimmed) {
117
+ return;
118
+ }
119
+ const catalogue = loadCatalogue();
120
+ const overrides = stripMeta(readCatalogue(overridesPath()));
121
+ const native = provider ? planeFor(catalogue, provider) : {};
122
+ const litellm = planeFor(catalogue, FALLBACK_PLANE);
123
+ const candidates = candidatesFor(trimmed, MODEL_ALIASES);
124
+ for (const id of candidates) {
125
+ const entry = overrides[id];
126
+ if (entry) {
127
+ return { entry, key: id, source: "override" };
128
+ }
129
+ }
130
+ for (const id of candidates) {
131
+ const entry = native[id];
132
+ if (entry) {
133
+ return { entry, key: id, source: "provider" };
134
+ }
135
+ }
136
+ for (const id of candidates) {
137
+ const entry = litellm[id];
138
+ if (entry) {
139
+ return { entry, key: id, source: "litellm" };
140
+ }
141
+ }
142
+ const slug = slugifyModelName(trimmed);
143
+ const fuzzyOverride = fuzzyFind(overrides, slug);
144
+ if (fuzzyOverride) {
145
+ return { ...fuzzyOverride, source: "override" };
146
+ }
147
+ const fuzzyNative = fuzzyFind(native, slug);
148
+ if (fuzzyNative) {
149
+ return { ...fuzzyNative, source: "provider" };
150
+ }
151
+ const fuzzyLitellm = fuzzyFind(litellm, slug);
152
+ if (fuzzyLitellm) {
153
+ return { ...fuzzyLitellm, source: "litellm" };
154
+ }
155
+ return;
156
+ }
157
+ function estimateCostUsd(provider, model, usage) {
158
+ const inputTokens = usage.inputTokens ?? 0;
159
+ const outputTokens = usage.outputTokens ?? 0;
160
+ const cacheReadTokens = usage.cacheReadTokens ?? 0;
161
+ const cacheWriteTokens = usage.cacheWriteTokens ?? 0;
162
+ if (!model || inputTokens <= 0 && outputTokens <= 0 && cacheReadTokens <= 0 && cacheWriteTokens <= 0) {
163
+ return { costUsd: null, billing: "unknown", pool: "unknown", source: "missing" };
164
+ }
165
+ const resolved = resolveModelPrice(provider, model);
166
+ if (!resolved) {
167
+ return { costUsd: null, billing: "unknown", pool: "unknown", source: "missing" };
168
+ }
169
+ const { entry, key, source } = resolved;
170
+ const pool = entry.pool ?? "unknown";
171
+ if (entry.billing === "included") {
172
+ return { costUsd: null, billing: "included", pool, source, catalogKey: key };
173
+ }
174
+ if (typeof entry.promptPer1M !== "number" || typeof entry.completionPer1M !== "number") {
175
+ return { costUsd: null, billing: entry.billing ?? "unknown", pool, source, catalogKey: key };
176
+ }
177
+ let costUsd = inputTokens / 1e6 * entry.promptPer1M + outputTokens / 1e6 * entry.completionPer1M;
178
+ if (typeof entry.cacheReadPer1M === "number" && cacheReadTokens > 0) {
179
+ costUsd += cacheReadTokens / 1e6 * entry.cacheReadPer1M;
180
+ }
181
+ if (typeof entry.cacheWritePer1M === "number" && cacheWriteTokens > 0) {
182
+ costUsd += cacheWriteTokens / 1e6 * entry.cacheWritePer1M;
183
+ }
184
+ return { costUsd, billing: "metered", pool, source, catalogKey: key };
185
+ }
186
+
187
+ export { FALLBACK_PLANE, mapPoolToNeutral, slugifyModelName, cataloguePath, overridesPath, loadCatalogue, planeMeta, catalogueMeta, resolveModelPrice, estimateCostUsd };