@yaag/cli 0.6.2 → 0.8.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.
Files changed (50) hide show
  1. package/README.md +31 -0
  2. package/assets/types/runtime/agent/agent.d.ts +16 -1
  3. package/assets/types/runtime/agent/define-agent.d.ts +20 -3
  4. package/assets/types/runtime/agent/spawn-extensions.d.ts +39 -0
  5. package/assets/types/runtime/agent/spawn-request.d.ts +24 -0
  6. package/assets/types/runtime/agent/spawn.d.ts +3 -0
  7. package/assets/types/runtime/ask/ask-exchange-events.d.ts +7 -1
  8. package/assets/types/runtime/ask/ask-exchange-options.d.ts +12 -0
  9. package/assets/types/runtime/ask/index.d.ts +1 -0
  10. package/assets/types/runtime/cassette/cassette-schema.d.ts +1 -0
  11. package/assets/types/runtime/cassette/cassette.d.ts +5 -0
  12. package/assets/types/runtime/cassette/replay-divergence.d.ts +10 -2
  13. package/assets/types/runtime/config/config-file.d.ts +22 -0
  14. package/assets/types/runtime/config/config-issues.d.ts +12 -0
  15. package/assets/types/runtime/config/config-paths.d.ts +22 -0
  16. package/assets/types/runtime/config/config-schema.d.ts +17 -0
  17. package/assets/types/runtime/config/effective-config.d.ts +42 -0
  18. package/assets/types/runtime/config/index.d.ts +8 -0
  19. package/assets/types/runtime/errors.d.ts +16 -2
  20. package/assets/types/runtime/events.d.ts +18 -0
  21. package/assets/types/runtime/extension/extension-paths.d.ts +10 -2
  22. package/assets/types/runtime/index.d.ts +4 -2
  23. package/assets/types/runtime/model/index.d.ts +8 -1
  24. package/assets/types/runtime/model/model-error-history.d.ts +20 -0
  25. package/assets/types/runtime/model/model-failure.d.ts +18 -0
  26. package/assets/types/runtime/model/model-fallback.d.ts +13 -0
  27. package/assets/types/runtime/model/model-match.d.ts +31 -0
  28. package/assets/types/runtime/model/model-resolution.d.ts +44 -6
  29. package/assets/types/runtime/model/model-swap.d.ts +27 -0
  30. package/assets/types/runtime/model/recorded-resolution.d.ts +37 -0
  31. package/assets/types/runtime/model/resolution-loop.d.ts +47 -0
  32. package/assets/types/runtime/run/run.d.ts +7 -0
  33. package/assets/types/runtime/summary/index.d.ts +1 -1
  34. package/assets/types/runtime/summary/summary-agent.d.ts +8 -0
  35. package/assets/types/runtime/summary/summary-fallbacks.d.ts +30 -0
  36. package/assets/types/runtime/summary/summary.d.ts +3 -1
  37. package/assets/types/runtime/transport/fake-transport.d.ts +9 -1
  38. package/assets/types/runtime/transport/index.d.ts +1 -0
  39. package/assets/types/runtime/transport/stderr-tail.d.ts +12 -0
  40. package/assets/types/runtime/transport/transport.d.ts +15 -0
  41. package/assets/types/runtime/types.d.ts +33 -5
  42. package/assets/types/runtime/wire-constants.d.ts +2 -0
  43. package/package.json +3 -3
  44. package/src/argv.ts +23 -4
  45. package/src/cli.ts +9 -0
  46. package/src/config/index.ts +8 -0
  47. package/src/config/program-directory.ts +34 -0
  48. package/src/config/run-config.ts +54 -0
  49. package/src/terminal/render.ts +3 -0
  50. package/src/terminal/run-invocation.ts +4 -1
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Public surface of the CLI's `config/` module: Program Directory discovery and
3
+ * the launcher's Effective Config read (ADR-0040).
4
+ * Files inside this directory import each other directly.
5
+ */
6
+
7
+ export { findProgramDirectory } from "./program-directory.ts";
8
+ export { loadRunConfig, type RunConfigRequest } from "./run-config.ts";
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Program Directory discovery for the launcher.
3
+ *
4
+ * The runtime's `config-paths.ts` never walks upward: it takes the Program
5
+ * Directory as an input. The CLI is the launcher, so the walk lives here
6
+ * (ADR-0040).
7
+ */
8
+ import { stat } from "node:fs/promises";
9
+ import { dirname, join, resolve } from "node:path";
10
+ import { PROJECT_CONFIG_DIR } from "@yaag/runtime";
11
+
12
+ /**
13
+ * The nearest directory at or above `startDirectory` that holds a `.yaag`
14
+ * directory, or `undefined` when the walk reaches the filesystem root.
15
+ *
16
+ * A `.yaag` file is not a marker: only a directory can hold a config file.
17
+ */
18
+ export async function findProgramDirectory(startDirectory: string): Promise<string | undefined> {
19
+ let directory = resolve(startDirectory);
20
+ for (;;) {
21
+ if (await hasMarker(directory)) return directory;
22
+ const parent = dirname(directory);
23
+ if (parent === directory) return undefined;
24
+ directory = parent;
25
+ }
26
+ }
27
+
28
+ async function hasMarker(directory: string): Promise<boolean> {
29
+ try {
30
+ return (await stat(join(directory, PROJECT_CONFIG_DIR))).isDirectory();
31
+ } catch {
32
+ return false;
33
+ }
34
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * The launcher's config read: it resolves the Program Directory of one Run and
3
+ * loads the Effective Config from the three layers (ADR-0040).
4
+ *
5
+ * `RunOptions.config` is read once, here, at Run start. Nothing else in the
6
+ * process reads a config file.
7
+ */
8
+ import { dirname, resolve } from "node:path";
9
+ import { type ConfigEnvironment, type EffectiveConfig, loadEffectiveConfig } from "@yaag/runtime";
10
+ import { findProgramDirectory } from "./program-directory.ts";
11
+
12
+ /** What one Run needs to know to find its config layers. */
13
+ export interface RunConfigRequest {
14
+ /** Absolute path of the program file; `undefined` for an Inline Program. */
15
+ readonly programFile: string | undefined;
16
+ /** Where an Inline Program starts its search; defaults to `process.cwd()`. */
17
+ readonly cwd?: string;
18
+ /** The `--config` value, absolute or relative to `cwd`. */
19
+ readonly configPath?: string;
20
+ /** `--no-config`: drops the Global and the Project layer only (spec rule 8). */
21
+ readonly noConfig?: boolean;
22
+ /** Environment for Global Config discovery; defaults to `process.env`. */
23
+ readonly env?: ConfigEnvironment;
24
+ }
25
+
26
+ /**
27
+ * Loads the Effective Config of one Run.
28
+ *
29
+ * The Program Directory search starts at the program file's directory, or at
30
+ * `cwd` for an Inline Program. `--no-config` skips the search: no discovered
31
+ * layer can contribute, so nothing must be looked for.
32
+ *
33
+ * Throws `YaagError("CONFIG_INVALID", …)` when a config file is missing at the
34
+ * explicit `--config` path, or when any layer is unreadable or invalid.
35
+ */
36
+ export async function loadRunConfig(request: RunConfigRequest): Promise<EffectiveConfig> {
37
+ const cwd = request.cwd ?? process.cwd();
38
+ const configPath =
39
+ request.configPath === undefined ? undefined : resolve(cwd, request.configPath);
40
+ // `--no-config` discovers nothing, so the upward walk is skipped: it would
41
+ // stat directory after directory for a layer that cannot contribute.
42
+ const programDirectory =
43
+ request.noConfig === true
44
+ ? undefined
45
+ : await findProgramDirectory(
46
+ request.programFile === undefined ? cwd : dirname(request.programFile),
47
+ );
48
+ return await loadEffectiveConfig({
49
+ ...(request.env === undefined ? {} : { env: request.env }),
50
+ ...(request.noConfig === true ? { noConfig: true } : {}),
51
+ ...(programDirectory === undefined ? {} : { programDirectory }),
52
+ ...(configPath === undefined ? {} : { configPath }),
53
+ });
54
+ }
@@ -39,6 +39,8 @@ function renderPlainEvent(event: LifecycleEventBody, mode: PlainRenderMode): str
39
39
  event.maxFrameGapMs === undefined ? "" : ` max gap ${seconds(event.maxFrameGapMs)}`;
40
40
  return `[${event.agent}] ask #${event.index + 1} ${event.ok ? "done" : "failed"} ${seconds(event.durationMs)}${gap}`;
41
41
  }
42
+ case "model_fallback":
43
+ return `[${event.agent}] model ${event.failedModel} ${event.reason} — falling back to ${event.resolvedModel}`;
42
44
  case "agent_exit":
43
45
  return `[${event.agent}] exit ${tokens(event.tokens)} ${cost(event.cost)}${event.incomplete ? " (killed mid-ask, cost incomplete)" : ""}`;
44
46
  case "run_end": {
@@ -58,6 +60,7 @@ function minimalEvent(type: LifecycleEventBody["type"]): boolean {
58
60
  type === "agent_spawn" ||
59
61
  type === "ask_start" ||
60
62
  type === "ask_end" ||
63
+ type === "model_fallback" ||
61
64
  type === "agent_exit" ||
62
65
  type === "run_end"
63
66
  );
@@ -5,7 +5,7 @@
5
5
  * Both presentation paths — the plain lines and the alt-screen tree — compose
6
6
  * it, so they cannot drift on artifact flags or on the result format.
7
7
  */
8
- import type { RunOptions, StampedEventSink } from "@yaag/runtime";
8
+ import type { EffectiveConfig, RunOptions, StampedEventSink } from "@yaag/runtime";
9
9
 
10
10
  /** Everything `yaag run` parsed for one Run. */
11
11
  export interface RunFlags {
@@ -18,6 +18,8 @@ export interface RunFlags {
18
18
  readonly record: string | undefined;
19
19
  readonly replay: string | undefined;
20
20
  readonly resume: string | undefined;
21
+ /** The Effective Config the launcher read at Run start (ADR-0040). */
22
+ readonly config: EffectiveConfig | undefined;
21
23
  readonly quiet: boolean;
22
24
  }
23
25
 
@@ -35,6 +37,7 @@ export function executeOptions(
35
37
  ...(flags.record === undefined ? {} : { record: flags.record }),
36
38
  ...(flags.replay === undefined ? {} : { replay: flags.replay }),
37
39
  ...(flags.resume === undefined ? {} : { resume: flags.resume }),
40
+ ...(flags.config === undefined ? {} : { config: flags.config }),
38
41
  signal,
39
42
  };
40
43
  }