@hypit/hypit 0.1.7 → 0.1.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hypit/hypit",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "homepage": "https://hypit.ai",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,6 +14,11 @@ invent targets, candidates or Provider choices.
14
14
  Human and JSON output answer the same command-specific question. `--json` changes encoding;
15
15
  `--verbose` expands scope. Compiler, Runtime and Repository objects are not default reports.
16
16
 
17
+ Argument errors use `CLI_USAGE` and point to the relevant `hypit help <command>`; JSON retains that
18
+ command in `error.help`. Unknown help topics fail explicitly. Runtime and execution failures retain
19
+ their own diagnostics and optional `--debug` trace. Result pagination changes only the `--before`
20
+ cursor on the current query, preserving its project, Source filter and other options.
21
+
17
22
  | Command | Default scope | Explicit detail |
18
23
  | --- | --- | --- |
19
24
  | `check` | Validation, targets and counts | `--verbose`: exported names/types and historical references |
@@ -113,6 +118,9 @@ flow.
113
118
  execution phases and Provider diagnostics. It reads a finished Result directly, without opening the
114
119
  Runtime; an active Build is read through Runtime control. The selected Repository handles file access.
115
120
  `--lines` limits the tail and the report states the omitted count; JSON carries records plus that count.
121
+ An unavailable log reports `source: "unavailable"` and exits unsuccessfully; a readable log with zero
122
+ records is a successful empty result. The human report distinguishes a finished Result with no log
123
+ from a lookup that still needs the Build's Runtime or correct project selection.
116
124
  `inspect` exposes an available log separately from authored Outputs. `hypit runtime logs` reads the
117
125
  Worker process log instead, for Runtime startup or process-level failures.
118
126
 
@@ -13,6 +13,7 @@ import type {
13
13
  RuntimeSelectionCommand,
14
14
  } from "./command.js";
15
15
  import type { CliColorMode, CliOutputOptions } from "./output.js";
16
+ import { CliUsageError } from "./usage-error.js";
16
17
 
17
18
  type RawOptions = {
18
19
  readonly presentation: CliOutputOptions;
@@ -48,6 +49,15 @@ type RawOptions = {
48
49
  const commonOptions = ["--json", "--color", "--no-color", "--verbose", "--debug"] as const;
49
50
 
50
51
  export function parseCommand(argv: readonly string[]): CliCommand {
52
+ try { return parseArguments(argv); }
53
+ catch (error) {
54
+ if (error instanceof CliUsageError) throw error;
55
+ throw new CliUsageError(error instanceof Error ? error.message : String(error),
56
+ argv[0] === undefined ? "hypit help" : `hypit help ${argv[0]}`, { cause: error });
57
+ }
58
+ }
59
+
60
+ function parseArguments(argv: readonly string[]): CliCommand {
51
61
  const [command, ...tail] = argv;
52
62
  switch (command) {
53
63
  case "check": {
@@ -246,7 +256,8 @@ export function parseCommand(argv: readonly string[]): CliCommand {
246
256
  ...optionalPackageRoot(options),
247
257
  };
248
258
  }
249
- default: throw new Error(usage());
259
+ default: throw new CliUsageError(command === undefined ? "A command is required"
260
+ : `Unknown command ${JSON.stringify(command)}`, "hypit help");
250
261
  }
251
262
  }
252
263
 
@@ -83,13 +83,19 @@ export async function runExecutionCommand(input: {
83
83
  const records = view?.records ?? [];
84
84
  const omitted = (view?.total ?? 0) - records.length;
85
85
  write({ format: "hypit.cli-logs@1", build: args.build, source, records, omittedRecords: omitted },
86
- view === undefined ? "No execution log recorded" : "Build execution log", "info",
86
+ view === undefined ? "Execution log unavailable" : "Build execution log", view === undefined ? "warning" : "info",
87
87
  [["Build", args.build], ["Source", source]], [
88
+ ...(view !== undefined ? [] : [finished
89
+ ? "This Result has no saved execution log."
90
+ : activeProfile === undefined
91
+ ? "No saved log found in this project. Select the Build's Runtime with --runtime <profile> to check active execution."
92
+ : "No log found in this project's Results or the selected Runtime. Check the Build id and project selection."]),
88
93
  ...(omitted > 0 ? [`Showing last ${records.length} records; ${omitted} earlier records omitted. Use --lines to read more.`] : []),
89
94
  ...records.map((record) => `${new Date(record.time).toISOString()} ${record.endpoint} ${record.command} ${
90
95
  record.kind === "phase" ? record.phase : record.kind === "diagnostic" || record.kind === "failed"
91
96
  ? `${record.kind}: ${record.message}` : record.kind}`),
92
97
  ]);
98
+ if (view === undefined) io.setExitCode?.(1);
93
99
  return;
94
100
  }
95
101
 
@@ -54,7 +54,9 @@ export async function runProjectResultCommand(input: {
54
54
  const label = item.title === undefined ? item.id : `${item.title} · ${item.id}`;
55
55
  const run = item.run === undefined ? "" : ` · ${item.run}`;
56
56
  return `${label}: ${item.outcome} · ${new Date(item.createdAt).toLocaleString()}${run} · ${item.targetCount} target${item.targetCount === 1 ? "" : "s"}`;
57
- }).concat(page.next === undefined ? [] : [`Older hypit builds --before ${page.next}`]));
57
+ }).concat(page.next === undefined ? [] : [
58
+ `Older Repeat this command with --before ${page.next}, keeping the other options.`,
59
+ ]));
58
60
  return;
59
61
  }
60
62
 
@@ -89,7 +91,9 @@ export async function runProjectResultCommand(input: {
89
91
  const label = item.title === undefined ? item.build : `${item.title} · ${item.build}`;
90
92
  return `${label}: ${item.outcome} · ${new Date(item.createdAt).toLocaleString()}`
91
93
  + (args.presentation.verbose ? ` · ${item.output.kind} · ${item.output.type}` : "");
92
- }).concat(page.next === undefined ? [] : [`Older hypit history ${args.outputName} --before ${page.next}`]));
94
+ }).concat(page.next === undefined ? [] : [
95
+ `Older Repeat this command with --before ${page.next}, keeping the other options.`,
96
+ ]));
93
97
  return;
94
98
  }
95
99
 
@@ -62,7 +62,8 @@ export async function runCli(
62
62
  distribution: CliDistribution,
63
63
  ): Promise<void> {
64
64
  if (argv.length === 0 || argv[0] === "help" || argv.includes("--help")) {
65
- const topic = argv[0] === "help" ? argv[1] : argv.includes("--help") ? argv[0] : undefined;
65
+ const topic = argv[0] === "help" ? argv[1] : argv[0] === "--help" ? undefined
66
+ : argv.includes("--help") ? argv[0] : undefined;
66
67
  writeCliHelp(io, topic);
67
68
  return;
68
69
  }
@@ -3,6 +3,7 @@ import { relative, resolve } from "node:path";
3
3
  import type { CanonicalValue } from "@hypit/protocol";
4
4
 
5
5
  import type { OperationalMachineView } from "./machine-view.js";
6
+ import { CliUsageError } from "./usage-error.js";
6
7
 
7
8
  export type CliTerminal = {
8
9
  readonly isTTY: boolean;
@@ -986,6 +987,7 @@ export function writeCliHelp(io: CliIo, topic?: string): void {
986
987
  io.write(`${selected.join("\n")}\n`);
987
988
  return;
988
989
  }
990
+ throw new CliUsageError(`Unknown help topic ${JSON.stringify(topic)}`, "hypit help");
989
991
  }
990
992
  io.write([
991
993
  colors.accent(colors.strong("Hypit")),
@@ -1044,6 +1046,7 @@ export function renderCliError(error: unknown, options: {
1044
1046
  error: {
1045
1047
  code,
1046
1048
  message: source.message,
1049
+ ...(source instanceof CliUsageError ? { help: source.help } : {}),
1047
1050
  ...(options.debug && trace !== undefined && trace.length > 0 ? { trace } : {}),
1048
1051
  },
1049
1052
  }, null, 2)}\n`;
@@ -1058,6 +1061,8 @@ export function renderCliError(error: unknown, options: {
1058
1061
  ];
1059
1062
  if (options.debug && trace !== undefined && trace.length > 0) {
1060
1063
  lines.push("", colors.dim(trace));
1064
+ } else if (source instanceof CliUsageError) {
1065
+ lines.push("", `Usage ${source.help}`);
1061
1066
  } else {
1062
1067
  lines.push("", colors.dim("Run with --debug to include the internal stack trace."));
1063
1068
  }
@@ -0,0 +1,8 @@
1
+ /** Argument errors point to public usage rather than an internal stack trace. */
2
+ export class CliUsageError extends Error {
3
+ readonly code = "CLI_USAGE";
4
+ constructor(message: string, readonly help: string, options?: ErrorOptions) {
5
+ super(message, options);
6
+ this.name = "CliUsageError";
7
+ }
8
+ }