@tech-leads-club/harness-toolkit 0.4.0 → 0.4.1
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 +50 -17
- package/dist/compact-before.mjs +60 -60
- package/dist/doctor.mjs +77 -77
- package/dist/help-topic.mjs +3 -3
- package/dist/init-project.mjs +86 -86
- package/dist/install-runtime.mjs +76 -76
- package/dist/lessons-cli.mjs +82 -82
- package/dist/obs-cli.mjs +73 -73
- package/dist/price-lookup.mjs +2 -2
- package/dist/prompt-submit.mjs +60 -60
- package/dist/refresh-model-prices.mjs +69 -69
- package/dist/response-after.mjs +61 -61
- package/dist/run.mjs +61 -61
- package/dist/session-end.mjs +65 -65
- package/dist/session-start.mjs +66 -66
- package/dist/shim.mjs +72 -72
- package/dist/stop.mjs +68 -68
- package/dist/subagent-start.mjs +59 -59
- package/dist/subagent-stop.mjs +61 -61
- package/dist/support.mjs +71 -71
- package/dist/tlc-cli.mjs +93 -93
- package/dist/tool-after.mjs +64 -64
- package/dist/tool-before.mjs +69 -69
- package/dist/tool-failure.mjs +60 -60
- package/dist/uninstall-runtime.mjs +4 -4
- package/package.json +1 -1
- package/src/core/core.facade.ts +7 -0
- package/src/core/policy/policy.shadow.ts +36 -40
- package/src/platform/paths.ts +57 -2
- package/src/providers/index.ts +1 -0
- package/tools/doctor.ts +12 -33
- package/tools/install-runtime.ts +15 -21
package/bin/tlc-cli.ts
CHANGED
|
@@ -9,18 +9,22 @@ import {
|
|
|
9
9
|
rmSync,
|
|
10
10
|
writeFileSync,
|
|
11
11
|
} from "node:fs";
|
|
12
|
-
import {
|
|
12
|
+
import { join } from "node:path";
|
|
13
13
|
import { coreFacade } from "../src/core/index.ts";
|
|
14
14
|
import { emitJson, JSON_FLAG, takeJsonFlag, unknownFlags } from "../src/platform/cli-output.ts";
|
|
15
15
|
import { linkDir, linkFile, seedConfig } from "../src/platform/links.ts";
|
|
16
16
|
import {
|
|
17
|
+
EXECUTABLE_EXTENSIONS,
|
|
18
|
+
executableOnPath,
|
|
17
19
|
flagsDir,
|
|
18
20
|
isOnPath,
|
|
19
21
|
launcherBinDir,
|
|
22
|
+
machineHome,
|
|
20
23
|
projectConfigPath,
|
|
21
24
|
projectStateDir,
|
|
22
25
|
providerConfigDirs,
|
|
23
26
|
runtimeHome,
|
|
27
|
+
sameLocation,
|
|
24
28
|
} from "../src/platform/paths.ts";
|
|
25
29
|
import { type Row, render, type Screen, type Section } from "../src/platform/screen.ts";
|
|
26
30
|
import { createStyle, PLAIN, type Style } from "../src/platform/style.ts";
|
|
@@ -760,24 +764,16 @@ const GATE_FIELDS: Record<string, GateField> = {
|
|
|
760
764
|
* name is first, so a POSIX `foo` is never beaten by a stray `foo.exe`
|
|
761
765
|
* ([/decisions/ad-097.md](/decisions/ad-097.md)).
|
|
762
766
|
*/
|
|
763
|
-
|
|
764
|
-
|
|
767
|
+
/**
|
|
768
|
+
* why this still exists beside `executableOnPath`: it also answers for a name that is already a path, which a PATH
|
|
769
|
+
* walk has nothing to say about. The walk itself is not repeated here
|
|
770
|
+
* ([/decisions/ad-101.md](/decisions/ad-101.md)).
|
|
771
|
+
*/
|
|
765
772
|
export function resolveExecutable(name: string, env: NodeJS.ProcessEnv = process.env): string | null {
|
|
766
|
-
const candidates = (base: string): string[] => EXECUTABLE_EXTENSIONS.map((ext) => `${base}${ext}`);
|
|
767
|
-
|
|
768
773
|
if (name.includes("/") || name.includes("\\")) {
|
|
769
|
-
return
|
|
770
|
-
}
|
|
771
|
-
for (const dir of (env.PATH ?? "").split(delimiter)) {
|
|
772
|
-
if (!dir) {
|
|
773
|
-
continue;
|
|
774
|
-
}
|
|
775
|
-
const found = candidates(join(dir, name)).find((candidate) => existsSync(candidate));
|
|
776
|
-
if (found) {
|
|
777
|
-
return found;
|
|
778
|
-
}
|
|
774
|
+
return EXECUTABLE_EXTENSIONS.map((ext) => `${name}${ext}`).find((c) => existsSync(c)) ?? null;
|
|
779
775
|
}
|
|
780
|
-
return
|
|
776
|
+
return executableOnPath(name, env);
|
|
781
777
|
}
|
|
782
778
|
|
|
783
779
|
/**
|
|
@@ -897,6 +893,29 @@ export function pricesHelpText(style: Style = PLAIN): string {
|
|
|
897
893
|
return render(pricesHelpScreen(), style);
|
|
898
894
|
}
|
|
899
895
|
|
|
896
|
+
/**
|
|
897
|
+
* The installed version, read from the runtime's own manifest.
|
|
898
|
+
*
|
|
899
|
+
* hazard: nothing showed it. `doctor` printed twenty rows and not one carried a version, and `update` on the npm
|
|
900
|
+
* route said `runtime → <path>` without naming what it was on or what it moved to
|
|
901
|
+
* ([/decisions/ad-101.md](/decisions/ad-101.md)).
|
|
902
|
+
*/
|
|
903
|
+
export function runtimeVersion(home: string): string | null {
|
|
904
|
+
try {
|
|
905
|
+
const raw = JSON.parse(readFileSync(join(home, "package.json"), "utf8")) as { version?: unknown };
|
|
906
|
+
return typeof raw.version === "string" ? raw.version : null;
|
|
907
|
+
} catch {
|
|
908
|
+
return null;
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
/** why one line: an unchanged version is the common case and reads better as a sentence than as two rows. */
|
|
913
|
+
export function versionMoveLine(before: string | null, after: string | null): string {
|
|
914
|
+
return before !== null && after !== null && before !== after
|
|
915
|
+
? `update: ${before} → ${after}`
|
|
916
|
+
: `update: already at ${after ?? before ?? "unknown"}`;
|
|
917
|
+
}
|
|
918
|
+
|
|
900
919
|
export function resolveHarnessRoot(): string {
|
|
901
920
|
const home = runtimeHome();
|
|
902
921
|
try {
|
|
@@ -995,6 +1014,18 @@ export function npmRootFailureMessage(home: string): string {
|
|
|
995
1014
|
* then reports it healthy while the command still does not exist.
|
|
996
1015
|
*/
|
|
997
1016
|
export function launcherLines(dest: string): string[] {
|
|
1017
|
+
/**
|
|
1018
|
+
* hazard: this linked unconditionally. An install to a throwaway `TLC_INSTALL_DEST` therefore pointed the
|
|
1019
|
+
* machine's `tlc` at that directory — measured: a proof-of-concept install into a temp directory left the
|
|
1020
|
+
* operator's command running from `/tmp`, and every `tlc harness ...` after it resolved its runtime there
|
|
1021
|
+
* ([/decisions/ad-101.md](/decisions/ad-101.md)).
|
|
1022
|
+
*
|
|
1023
|
+
* invariant: only the machine's own runtime home owns the command on `PATH`. Installing somewhere else is a
|
|
1024
|
+
* deliberate act and must not reach into anybody's shell.
|
|
1025
|
+
*/
|
|
1026
|
+
if (!sameLocation(dest, machineHome())) {
|
|
1027
|
+
return [`tlc not linked — ${dest} is not this machine's runtime home`];
|
|
1028
|
+
}
|
|
998
1029
|
const dir = launcherBinDir();
|
|
999
1030
|
const source = join(dest, "bin", "tlc");
|
|
1000
1031
|
// hazard: `symlinkSync` happily creates a link to a path that is not there, and `existsSync` on a dangling link
|
|
@@ -1369,7 +1400,8 @@ function runUpdate(root: string): never {
|
|
|
1369
1400
|
const dest = resolveHarnessRoot();
|
|
1370
1401
|
const revisionBefore = runtimeRevision(dest).revision;
|
|
1371
1402
|
const home = runtimeHome();
|
|
1372
|
-
|
|
1403
|
+
const versionBefore = runtimeVersion(dest);
|
|
1404
|
+
console.log(`update: runtime → ${dest} (${versionBefore ?? "unknown"})`);
|
|
1373
1405
|
|
|
1374
1406
|
if (!existsSync(join(dest, "bin", "tlc-exec.mjs"))) {
|
|
1375
1407
|
console.error(`update: missing install at ${home}`);
|
|
@@ -1414,6 +1446,7 @@ function runUpdate(root: string): never {
|
|
|
1414
1446
|
if ((sync.status ?? 1) !== 0) {
|
|
1415
1447
|
process.exit(sync.status ?? 1);
|
|
1416
1448
|
}
|
|
1449
|
+
console.log(versionMoveLine(versionBefore, runtimeVersion(dest)));
|
|
1417
1450
|
} else if (kind === "unmanaged") {
|
|
1418
1451
|
console.log(unmanagedRuntimeMessage(dest));
|
|
1419
1452
|
} else {
|