@tech-leads-club/harness-toolkit 0.3.3 → 0.3.4

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/bin/tlc-cli.ts CHANGED
@@ -936,18 +936,24 @@ export function globalPackageRoot(
936
936
  * invariant: the *package's* launcher runs the materialisation, not the runtime home's. A release that fixes
937
937
  * `install` has to be able to deliver that fix, and the old code cannot do it.
938
938
  *
939
- * invariant: both ends are named explicitly — `TLC_ORIGIN` is where the code comes from and `TLC_INSTALL_DEST` is
940
- * where it goes because each of them defaults to the same conventional home when left unsaid, which is exactly
941
- * how this became a no-op.
939
+ * invariant: only the **source** is named. `TLC_ORIGIN` is the one end this can know; the destination belongs to
940
+ * `installDest`, which exists because on a first npm run the *resolved* home is the package itself
941
+ * ([/decisions/ad-056.md](/decisions/ad-056.md)).
942
+ *
943
+ * hazard: the first version of this named the destination too, as `runtimeHome()`, and walked straight into that.
944
+ * On a clean machine it wrote `config.json` and the price catalogue into
945
+ * `node_modules/@tech-leads-club/harness-toolkit`, copied nothing, and then crashed writing hooks — Node refuses
946
+ * to strip types under `node_modules` ([/decisions/ad-098.md](/decisions/ad-098.md)).
942
947
  */
943
- export function npmSyncPlan(
944
- packageRoot: string,
945
- dest: string,
946
- ): { command: string; args: string[]; env: Record<string, string> } {
948
+ export function npmSyncPlan(packageRoot: string): {
949
+ command: string;
950
+ args: string[];
951
+ env: Record<string, string>;
952
+ } {
947
953
  return {
948
954
  command: process.execPath,
949
955
  args: [join(packageRoot, "bin", "tlc-exec.mjs"), "install-runtime"],
950
- env: { TLC_ORIGIN: packageRoot, TLC_INSTALL_DEST: dest },
956
+ env: { TLC_ORIGIN: packageRoot },
951
957
  };
952
958
  }
953
959
 
@@ -1044,6 +1050,7 @@ export type Action =
1044
1050
  | { kind: "prices-refresh"; scope: string }
1045
1051
  | { kind: "prices-lookup"; modelId: string }
1046
1052
  | { kind: "entry"; entry: string; args: string[] }
1053
+ | { kind: "install"; args: string[] }
1047
1054
  | { kind: "unknown"; cmd: string };
1048
1055
 
1049
1056
  export function route(args: string[]): Action {
@@ -1162,7 +1169,7 @@ export function route(args: string[]): Action {
1162
1169
  case "init":
1163
1170
  return { kind: "entry", entry: "init-project", args: args.slice(1) };
1164
1171
  case "install":
1165
- return { kind: "entry", entry: "install-runtime", args: args.slice(1) };
1172
+ return { kind: "install", args: args.slice(1) };
1166
1173
  // why: the exit has to be as easy to find as the entrance. An operator who cannot get the harness off their
1167
1174
  // machine without hand-editing settings.json will not try it on a second one
1168
1175
  // ([/decisions/ad-066.md](/decisions/ad-066.md)).
@@ -1353,7 +1360,7 @@ function runUpdate(root: string): never {
1353
1360
  console.error(npmRootFailureMessage(home));
1354
1361
  process.exit(1);
1355
1362
  }
1356
- const plan = npmSyncPlan(packageRoot, home);
1363
+ const plan = npmSyncPlan(packageRoot);
1357
1364
  const sync = spawnSync(plan.command, plan.args, {
1358
1365
  stdio: "inherit",
1359
1366
  env: { ...process.env, ...plan.env },
@@ -1451,6 +1458,31 @@ function runEntry(entry: string, toolArgs: string[], root: string): never {
1451
1458
  process.exit(r.status ?? 1);
1452
1459
  }
1453
1460
 
1461
+ /**
1462
+ * `install`, which is the only entry that must run from the *package* rather than from the runtime it is about to
1463
+ * replace.
1464
+ *
1465
+ * hazard: it went through `runEntry`, so the runtime home's own launcher ran the runtime home's own
1466
+ * `install-runtime`, whose source and destination then resolved to the same directory. Measured: package at 0.3.3,
1467
+ * runtime left on 0.3.1, with the command reporting success — and this is the recovery route the README and every
1468
+ * failure message name ([/decisions/ad-098.md](/decisions/ad-098.md)).
1469
+ *
1470
+ * invariant: `--link` stays local. It points the runtime at the checkout the operator is standing in, so its
1471
+ * source is the working directory and never the package.
1472
+ */
1473
+ function runInstall(toolArgs: string[], root: string): never {
1474
+ const packageRoot = toolArgs.includes("--link") ? null : globalPackageRoot();
1475
+ if (packageRoot === null) {
1476
+ runEntry("install-runtime", toolArgs, root);
1477
+ }
1478
+ const plan = npmSyncPlan(packageRoot);
1479
+ const r = spawnSync(plan.command, [...plan.args, ...toolArgs], {
1480
+ stdio: "inherit",
1481
+ env: { ...process.env, ...plan.env, TLC_PROJECT_DIR: root },
1482
+ });
1483
+ process.exit(r.status ?? 1);
1484
+ }
1485
+
1454
1486
  function main(argv: string[]): void {
1455
1487
  const root = resolveProjectRoot();
1456
1488
  const group = (argv[0] ?? "").toLowerCase();
@@ -1614,6 +1646,9 @@ function main(argv: string[]): void {
1614
1646
  case "prices-lookup":
1615
1647
  runEntry("price-lookup", json ? [action.modelId, JSON_FLAG] : [action.modelId], root);
1616
1648
  break;
1649
+ case "install":
1650
+ runInstall(action.args, root);
1651
+ break;
1617
1652
  case "entry":
1618
1653
  runEntry(action.entry, json ? [...action.args, JSON_FLAG] : action.args, root);
1619
1654
  break;
package/dist/tlc-cli.mjs CHANGED
@@ -7717,11 +7717,11 @@ function globalPackageRoot(probe = {
7717
7717
  const candidate = join27(root, ...NPM_PACKAGE.split("/"));
7718
7718
  return probe.exists(candidate) ? candidate : null;
7719
7719
  }
7720
- function npmSyncPlan(packageRoot, dest) {
7720
+ function npmSyncPlan(packageRoot) {
7721
7721
  return {
7722
7722
  command: process.execPath,
7723
7723
  args: [join27(packageRoot, "bin", "tlc-exec.mjs"), "install-runtime"],
7724
- env: { TLC_ORIGIN: packageRoot, TLC_INSTALL_DEST: dest }
7724
+ env: { TLC_ORIGIN: packageRoot }
7725
7725
  };
7726
7726
  }
7727
7727
  function npmRootFailureMessage(home) {
@@ -7869,7 +7869,7 @@ detail: tlc harness help prices`);
7869
7869
  case "init":
7870
7870
  return { kind: "entry", entry: "init-project", args: args.slice(1) };
7871
7871
  case "install":
7872
- return { kind: "entry", entry: "install-runtime", args: args.slice(1) };
7872
+ return { kind: "install", args: args.slice(1) };
7873
7873
  case "uninstall":
7874
7874
  return { kind: "entry", entry: "uninstall-runtime", args: args.slice(1) };
7875
7875
  case "why":
@@ -7991,7 +7991,7 @@ function runUpdate(root) {
7991
7991
  console.error(npmRootFailureMessage(home));
7992
7992
  process.exit(1);
7993
7993
  }
7994
- const plan = npmSyncPlan(packageRoot, home);
7994
+ const plan = npmSyncPlan(packageRoot);
7995
7995
  const sync = spawnSync(plan.command, plan.args, {
7996
7996
  stdio: "inherit",
7997
7997
  env: { ...process.env, ...plan.env }
@@ -8061,6 +8061,18 @@ function runEntry(entry, toolArgs, root) {
8061
8061
  });
8062
8062
  process.exit(r.status ?? 1);
8063
8063
  }
8064
+ function runInstall(toolArgs, root) {
8065
+ const packageRoot = toolArgs.includes("--link") ? null : globalPackageRoot();
8066
+ if (packageRoot === null) {
8067
+ runEntry("install-runtime", toolArgs, root);
8068
+ }
8069
+ const plan = npmSyncPlan(packageRoot);
8070
+ const r = spawnSync(plan.command, [...plan.args, ...toolArgs], {
8071
+ stdio: "inherit",
8072
+ env: { ...process.env, ...plan.env, TLC_PROJECT_DIR: root }
8073
+ });
8074
+ process.exit(r.status ?? 1);
8075
+ }
8064
8076
  function main(argv) {
8065
8077
  const root = resolveProjectRoot();
8066
8078
  const group = (argv[0] ?? "").toLowerCase();
@@ -8219,6 +8231,9 @@ function main(argv) {
8219
8231
  case "prices-lookup":
8220
8232
  runEntry("price-lookup", json ? [action.modelId, JSON_FLAG] : [action.modelId], root);
8221
8233
  break;
8234
+ case "install":
8235
+ runInstall(action.args, root);
8236
+ break;
8222
8237
  case "entry":
8223
8238
  runEntry(action.entry, json ? [...action.args, JSON_FLAG] : action.args, root);
8224
8239
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tech-leads-club/harness-toolkit",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
4
4
  "type": "module",
5
5
  "description": "Multi-provider agent steering: gates, follow-up, handoff, policy",
6
6
  "keywords": [