@open-tomato/rafa 0.44.0 → 0.46.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 (142) hide show
  1. package/README.md +280 -42
  2. package/dist/PROMPT.md +18 -1
  3. package/dist/adapters/logger/settings.d.ts +132 -0
  4. package/dist/bugs/closest.d.ts +19 -0
  5. package/dist/bugs/fenced.d.ts +8 -0
  6. package/dist/bugs/places.d.ts +20 -0
  7. package/dist/bugs/record.d.ts +145 -0
  8. package/dist/bugs/title.d.ts +83 -0
  9. package/dist/bundled/agents/doc-updater.md +17 -3
  10. package/dist/bundled/agents/loop-implementer.md +14 -2
  11. package/dist/bundled/operators/skills/rafa-stretch-pit-stop/SKILL.md +10 -3
  12. package/dist/bundled/operators/skills/rafa-stretch-sweep/SKILL.md +5 -0
  13. package/dist/bundled/skills/dev-planner/SKILL.md +120 -24
  14. package/dist/bundled/skills/documentation/SKILL.md +2 -12
  15. package/dist/cli.js +72387 -59411
  16. package/dist/config/entry.d.ts +119 -0
  17. package/dist/config/index.d.ts +36 -0
  18. package/dist/config/index.js +51 -0
  19. package/dist/config/shape.d.ts +232 -0
  20. package/dist/config-registry.d.ts +127 -0
  21. package/dist/config-schema-board-project.d.ts +157 -0
  22. package/dist/config-schema-bugs.d.ts +71 -0
  23. package/dist/config-schema-errors.d.ts +54 -0
  24. package/dist/config-schema-features.d.ts +64 -0
  25. package/dist/config-schema-hub.d.ts +150 -0
  26. package/dist/config-schema-issues.d.ts +95 -0
  27. package/dist/config-schema-logger.d.ts +91 -0
  28. package/dist/config-schema-loop-continue.d.ts +122 -0
  29. package/dist/config-schema-loop-retries.d.ts +94 -0
  30. package/dist/config-schema-release.d.ts +307 -0
  31. package/dist/config-schema-tests.d.ts +170 -0
  32. package/dist/config-schema-triage.d.ts +142 -0
  33. package/dist/config-schema-wrap-up.d.ts +96 -0
  34. package/dist/core/command/command.d.ts +228 -0
  35. package/dist/core/command/confirm.d.ts +67 -0
  36. package/dist/core/command/index.d.ts +112 -0
  37. package/dist/core/command/lazy.d.ts +54 -0
  38. package/dist/core/command/registry-types.d.ts +96 -0
  39. package/dist/core/command/running.d.ts +96 -0
  40. package/dist/core/command/spends.d.ts +39 -0
  41. package/dist/core/command/types.d.ts +92 -0
  42. package/dist/core/command/version.d.ts +4 -0
  43. package/dist/core/config/branch-template.d.ts +20 -0
  44. package/dist/core/config/config-items.d.ts +86 -0
  45. package/dist/core/config/config-load.d.ts +47 -0
  46. package/dist/core/config/config-origins.d.ts +57 -0
  47. package/dist/core/config/config-readers.d.ts +167 -0
  48. package/dist/core/config/config-schema.d.ts +207 -0
  49. package/dist/core/config/config-sections.d.ts +493 -0
  50. package/dist/core/config/config.d.ts +320 -0
  51. package/dist/core/config/core-section.d.ts +39 -0
  52. package/dist/core/config/dangerous.d.ts +58 -0
  53. package/dist/core/config/default-routing.d.ts +16 -0
  54. package/dist/core/config/index.d.ts +141 -0
  55. package/dist/core/config/scope.d.ts +42 -0
  56. package/dist/core/config/section.d.ts +206 -0
  57. package/dist/core/config/sections.d.ts +45 -0
  58. package/dist/core/config/standard-schema.d.ts +27 -0
  59. package/dist/core/git/commit.d.ts +232 -0
  60. package/dist/core/git/gh-runner.d.ts +24 -0
  61. package/dist/core/git/git.d.ts +22 -0
  62. package/dist/core/git/index.d.ts +85 -0
  63. package/dist/core/loop/claude.d.ts +388 -0
  64. package/dist/core/loop/hop-record.d.ts +52 -0
  65. package/dist/core/loop/index.d.ts +179 -0
  66. package/dist/core/loop/session-env.d.ts +20 -0
  67. package/dist/core/loop/session-record-parse.d.ts +63 -0
  68. package/dist/core/loop/sessions.d.ts +408 -0
  69. package/dist/core/loop/suite-failure.d.ts +25 -0
  70. package/dist/core/output/active.d.ts +100 -0
  71. package/dist/core/output/stream.d.ts +20 -0
  72. package/dist/core/output/text.d.ts +55 -0
  73. package/dist/core/plan/block-reader.d.ts +46 -0
  74. package/dist/core/plan/blocks.d.ts +139 -0
  75. package/dist/core/plan/declaration.d.ts +366 -0
  76. package/dist/core/plan/plan-stamp.d.ts +75 -0
  77. package/dist/core/runtime/identity.d.ts +21 -0
  78. package/dist/core/runtime/index.d.ts +46 -0
  79. package/dist/effort/store/bring-forward.d.ts +131 -0
  80. package/dist/effort/store/check-rows.d.ts +31 -0
  81. package/dist/effort/store/commit-stats.d.ts +42 -0
  82. package/dist/effort/store/copy.d.ts +35 -0
  83. package/dist/effort/store/development-build.d.ts +105 -0
  84. package/dist/effort/store/effort-levels.d.ts +13 -0
  85. package/dist/effort/store/findings.d.ts +214 -0
  86. package/dist/effort/store/fix-schema.d.ts +184 -0
  87. package/dist/effort/store/index.js +10 -7
  88. package/dist/effort/store/location.d.ts +44 -0
  89. package/dist/effort/store/merge-commit-gaps.d.ts +68 -0
  90. package/dist/effort/store/merge-conflicts.d.ts +91 -0
  91. package/dist/effort/store/merge-rules.d.ts +82 -0
  92. package/dist/effort/store/merge-store.d.ts +211 -0
  93. package/dist/effort/store/merge-union.d.ts +92 -0
  94. package/dist/effort/store/migrate.d.ts +146 -0
  95. package/dist/effort/store/migrations.d.ts +92 -0
  96. package/dist/effort/store/ndjson-files.d.ts +114 -0
  97. package/dist/effort/store/origins.d.ts +116 -0
  98. package/dist/effort/store/plan-stubs.d.ts +79 -0
  99. package/dist/effort/store/rebuild-aside.d.ts +172 -0
  100. package/dist/effort/store/schema-plan.d.ts +102 -0
  101. package/dist/effort/store/session-row-types.d.ts +64 -0
  102. package/dist/effort/store/settings.d.ts +13 -0
  103. package/dist/effort/store/sqlite.d.ts +340 -0
  104. package/dist/effort/store/store-generation.d.ts +17 -0
  105. package/dist/effort/store/store-identity.d.ts +220 -0
  106. package/dist/effort/store/store-meta.d.ts +305 -0
  107. package/dist/effort/store/store-replaced.d.ts +72 -0
  108. package/dist/effort/store/types.d.ts +223 -0
  109. package/dist/errors/codes.d.ts +56 -0
  110. package/dist/errors/rafa-codes.d.ts +36 -0
  111. package/dist/index-2a7nb3an.js +125 -0
  112. package/dist/{index-57mmzkcn.js → index-39kbcw68.js} +516 -217
  113. package/dist/{index-nv34ptht.js → index-77ajfffn.js} +14 -9
  114. package/dist/index-cy98y87p.js +2597 -0
  115. package/dist/index-gqz4jn6j.js +13447 -0
  116. package/dist/index-gvek4r8m.js +710 -0
  117. package/dist/index-j4k2vdz3.js +1125 -0
  118. package/dist/index-jh1r4kcn.js +1067 -0
  119. package/dist/index-ykggr043.js +540 -0
  120. package/dist/index-z1w83f81.js +4 -0
  121. package/dist/index.js +16091 -22798
  122. package/dist/learning/index.js +5 -6
  123. package/dist/plan/index.js +12 -11
  124. package/dist/plan-prompt.md +11 -2
  125. package/dist/ports/index.d.ts +732 -0
  126. package/dist/ports/learning.d.ts +101 -0
  127. package/dist/ports/log-level.d.ts +13 -0
  128. package/dist/ports/spec-review.d.ts +66 -0
  129. package/dist/pr/checks.d.ts +133 -0
  130. package/dist/pr/types.d.ts +422 -0
  131. package/dist/ready-4f8edezt.js +2016 -0
  132. package/dist/release-templates/release-bot-fragment.yml +153 -0
  133. package/dist/release-templates/release-publish.yml +110 -0
  134. package/dist/release-templates/release-settle.yml +122 -0
  135. package/dist/release-templates/release-tag.yml +102 -0
  136. package/dist/report/parse.d.ts +415 -0
  137. package/dist/schema/project-id.d.ts +79 -0
  138. package/dist/schema/tiers.d.ts +107 -0
  139. package/package.json +42 -4
  140. package/dist/index-6q30dtgm.js +0 -6342
  141. package/dist/index-cknayrpc.js +0 -2414
  142. package/dist/index-hf2k497d.js +0 -16
@@ -0,0 +1,119 @@
1
+ /**
2
+ * One config entry and the list of them a config module exports:
3
+ * {@link ConfigEntry}, rafa's own deep partial of the nested file shape
4
+ * `ConfigShape` (`shape.ts`), {@link Config}, {@link defineConfig}, and
5
+ * {@link entryOf}, which nests dotted keys into an entry.
6
+ *
7
+ * ## What an entry may hold
8
+ *
9
+ * An entry holds any part of the shape, every key at every depth
10
+ * optional, and two more forms the merge reads:
11
+ *
12
+ * - `false` at an id of a keyed map (`routing`, `tiers.skills`,
13
+ * `tiers.agents`, `logger.modules`) overrides what an earlier entry
14
+ * gave that id, so `{ logger: { modules: { board: false } } }` drops
15
+ * what an earlier entry gave `board`. Where the map takes `false` as a
16
+ * value (`routing`, the `tiers` pins) the loader keeps it as one, so it
17
+ * also shadows a lower layer's row, as in a YAML file; where it does
18
+ * not (`logger.modules`) the id is removed (`config-load.ts` in
19
+ * `packages/rafa/src/core/config/`). A named key takes `false` only where its own
20
+ * value does (`loop.retries`), never to remove it.
21
+ * - `{ $replace: true, …rest }` at any mapping below the top replaces
22
+ * that mapping whole with `rest`, discarding what earlier entries put
23
+ * there. On a scalar or a list it is a type error, since a later
24
+ * entry's list replaces an earlier one whole already. Inside `rest`
25
+ * neither form is read again: `rest` is a plain deep partial.
26
+ *
27
+ * These are the rules `@open-tomato/define-config`'s `merge` reads and
28
+ * its own `ConfigEntry` types. The type is declared here rather than
29
+ * imported so the `./config` subpath's declaration names nothing outside
30
+ * rafa. Its shapes follow that package's: one mapped type over every key
31
+ * with `$replace` beside them, never the named keys intersected with a
32
+ * keyed map's index signature, which that package's notes give as
33
+ * letting a stray `true` past at a map id.
34
+ *
35
+ * ## Values
36
+ *
37
+ * {@link defineConfig} is the identity: it answers the very list it is
38
+ * given and exists for its parameter type, so an editor flags a wrong
39
+ * key or value as the file is written. {@link entryOf} builds an entry
40
+ * from dotted keys, as `index.ts`'s `defaults` is built.
41
+ */
42
+ import type { ConfigShape } from './shape.js';
43
+ /** A value an entry never descends into: a scalar, or a list, which replaces whole. */
44
+ type EntryLeaf = string | number | boolean | bigint | symbol | null | undefined | readonly unknown[];
45
+ /** True when `K` is an index signature's key, an id of a keyed map, rather than a named key. */
46
+ type IsMapId<K> = string extends K ? true : number extends K ? true : false;
47
+ /** The value type of `T`'s string index signature, or `never` when it has none. */
48
+ type MapValue<T> = string extends keyof T ? T extends {
49
+ readonly [id: string]: infer V;
50
+ } ? V : never : never;
51
+ /** Every key of `T`, optional, its index signature included: the skeleton the shapes below map over. */
52
+ type Keys<T> = {
53
+ [K in keyof T]?: 0;
54
+ };
55
+ /** `T` with every key at every depth optional, leaves whole: what `rest` of a `$replace` holds. */
56
+ type PartialOf<T> = T extends EntryLeaf ? T : T extends object ? {
57
+ [K in keyof T]?: PartialOf<T[K]>;
58
+ } : T;
59
+ /** Maps skeleton `S` to a replacing mapping: `$replace` itself, then a deep partial of each key. */
60
+ type ReplaceShape<S, T> = {
61
+ [K in keyof S]: K extends '$replace' ? true : IsMapId<K> extends true ? PartialOf<MapValue<T>> | true | undefined : PartialOf<T[K & keyof T]>;
62
+ };
63
+ /**
64
+ * `{ $replace: true, …rest }` standing in for a mapping of type `T`;
65
+ * `never` for a leaf, so a `$replace` on a scalar or a list is refused.
66
+ * Over a keyed map the index signature admits `true` beside each id's
67
+ * value, since `$replace` is checked against it too.
68
+ */
69
+ type Replace<T> = T extends EntryLeaf ? never : T extends object ? ReplaceShape<{
70
+ $replace: 0;
71
+ } & Keys<T>, T> : never;
72
+ /** What an entry may set at key `K` of a mapping of type `T`. */
73
+ type EntryAt<T, K> = IsMapId<K> extends true ? EntryOf<MapValue<T>> | Replace<MapValue<T>> | false | undefined : EntryOf<T[K & keyof T]> | Replace<T[K & keyof T]>;
74
+ /** Maps skeleton `S`, with its modifiers, to the values an entry sets. */
75
+ type EntryShape<S, T> = {
76
+ [K in keyof S]: EntryAt<T, K>;
77
+ };
78
+ /**
79
+ * An entry for a value of type `T`: a leaf whole, a mapping key by key
80
+ * with `false` at a map id and `$replace` below it; see the module note.
81
+ *
82
+ * @typeParam T - The shape, or any part of it.
83
+ */
84
+ export type EntryOf<T> = T extends EntryLeaf ? T : T extends object ? EntryShape<Keys<T>, T> : T;
85
+ /** One config entry: a deep partial of {@link ConfigShape}; see the module note. */
86
+ export type ConfigEntry = EntryOf<ConfigShape>;
87
+ /** A config module's default export: its entries, applied in order over rafa's defaults. */
88
+ export type Config = readonly ConfigEntry[];
89
+ /**
90
+ * Declares a config's entries. At run time the identity: it answers the
91
+ * very list it is given, unchanged.
92
+ *
93
+ * @example
94
+ * ```ts
95
+ * export default defineConfig([{ naming: { branch: 'work/{stub}' } }]);
96
+ * ```
97
+ *
98
+ * @param entries - The entries, in the order they apply.
99
+ * @returns `entries`, the same list.
100
+ */
101
+ export declare function defineConfig(entries: Config): Config;
102
+ /**
103
+ * Nests dotted keys into one entry: `[['plan.inject', 'task']]` into
104
+ * `{ plan: { inject: 'task' } }`, every mapping frozen, keys in the
105
+ * order first named. The values are taken as given, already in the
106
+ * file's spelling. Throws on an empty key or segment, on a key given
107
+ * twice, and on a key that is both a value and a mapping (`a` beside
108
+ * `a.b`).
109
+ *
110
+ * The answer is typed {@link ConfigEntry} on the caller's word:
111
+ * nothing here checks a key against the shape. `index.ts`'s `defaults`
112
+ * is built from the registry's own keys, and `index.test.ts` reads each
113
+ * value back through its setting's reader.
114
+ *
115
+ * @param pairs - Each dotted key with its value.
116
+ * @returns A new frozen entry.
117
+ */
118
+ export declare function entryOf(pairs: readonly (readonly [key: string, value: unknown])[]): ConfigEntry;
119
+ export {};
@@ -0,0 +1,36 @@
1
+ /**
2
+ * The `./config` subpath, `@open-tomato/rafa/config`: what a
3
+ * `rafa.config.ts` or `rafa.config.mjs` imports to type its entries.
4
+ *
5
+ * - `Config`, the list of entries a config module exports, each a
6
+ * `ConfigEntry`, rafa's deep partial of the nested file shape
7
+ * `ConfigShape` (`entry.ts`, `shape.ts`).
8
+ * - `defineConfig`, the identity, typed for its parameter.
9
+ * - {@link defaults}, the one entry holding every setting's default.
10
+ *
11
+ * ## The defaults entry
12
+ *
13
+ * {@link defaults} is built from the registry (`src/config-registry.ts`):
14
+ * each setting's file key, nested, holding its value from
15
+ * `CONFIG_DEFAULTS` in the file's spelling ({@link fileValueOf}). A
16
+ * setting whose default is null (`pr.base`, `hub.url`) is left out: no
17
+ * reader accepts null, and an absent key is what null stands for.
18
+ * `index.test.ts` reads every value back through its setting's reader
19
+ * to the default it came from.
20
+ *
21
+ * Importing this module imports the registry, so the sections are
22
+ * registered with core as `src/rafa.ts` and `src/index.ts` register
23
+ * them. `ConfigShape` does not lean on that import for its keys:
24
+ * `shape.ts` composes it from each section's exported interface by
25
+ * `import type`, so the declaration emitted for `shape.ts` imports every
26
+ * section's emitted `.d.ts` and `ConfigShape` names every section's keys
27
+ * in the published declarations as in a program built from source
28
+ * (`shape.test.ts` reads `ConfigShape['hub']['url']` as `string` from
29
+ * declarations emitted over this file).
30
+ */
31
+ import type { ConfigEntry } from './entry.js';
32
+ export type { Config, ConfigEntry } from './entry.js';
33
+ export type { ConfigShape } from './shape.js';
34
+ export { defineConfig } from './entry.js';
35
+ /** Every setting's default, as one entry; see the module note. */
36
+ export declare const defaults: ConfigEntry;
@@ -0,0 +1,51 @@
1
+ // @bun
2
+ import {
3
+ CONFIG_DEFAULTS,
4
+ SETTINGS,
5
+ SETTING_NAMES
6
+ } from "../index-j4k2vdz3.js";
7
+ import"../index-gvek4r8m.js";
8
+ import"../index-ykggr043.js";
9
+ import"../index-z1w83f81.js";
10
+
11
+ // src/config/entry.ts
12
+ function defineConfig(entries) {
13
+ return entries;
14
+ }
15
+ function nest(placed, above) {
16
+ const heads = [...new Set(placed.map(([[head]]) => head ?? ""))];
17
+ return Object.freeze(Object.fromEntries(heads.map((head) => {
18
+ const key = above === "" ? head : `${above}.${head}`;
19
+ const under = placed.filter(([[first]]) => first === head);
20
+ const [leaf, ...more] = under.filter(([path]) => path.length === 1);
21
+ if (leaf === undefined)
22
+ return [head, nest(under.map(([path, value]) => [path.slice(1), value]), key)];
23
+ if (more.length > 0 || under.length > 1)
24
+ throw new Error(`rafa config: ${key} is given twice, or as a value and a mapping`);
25
+ return [head, leaf[1]];
26
+ })));
27
+ }
28
+ function entryOf(pairs) {
29
+ const placed = pairs.map(([key, value]) => {
30
+ const path = key.split(".");
31
+ if (path.some((segment) => segment === ""))
32
+ throw new Error(`rafa config: ${JSON.stringify(key)} is no dotted key`);
33
+ return [path, value];
34
+ });
35
+ return nest(placed, "");
36
+ }
37
+
38
+ // src/config/index.ts
39
+ var COMMA_SEPARATED = new Set(["settingSources"]);
40
+ function fileValueOf(setting, value) {
41
+ if (value instanceof Map)
42
+ return Object.freeze(Object.fromEntries(value));
43
+ if (COMMA_SEPARATED.has(setting) && Array.isArray(value))
44
+ return value.join(",");
45
+ return value;
46
+ }
47
+ var defaults = entryOf(SETTING_NAMES.filter((setting) => CONFIG_DEFAULTS[setting] !== null).map((setting) => [SETTINGS[setting].key, fileValueOf(setting, CONFIG_DEFAULTS[setting])]));
48
+ export {
49
+ defineConfig,
50
+ defaults
51
+ };
@@ -0,0 +1,232 @@
1
+ /**
2
+ * The nested file shape: {@link ConfigShape}, every key a config file
3
+ * writes, nested as the file nests it (`plan: { inject: 'stage' }` for
4
+ * `plan.inject`), each leaf typed as the file spells it. It is the type a
5
+ * `rafa.config.ts` entry is a deep partial of (`entry.ts`), and the
6
+ * `./config` subpath (`index.ts`) publishes it.
7
+ *
8
+ * ## The file's spelling, not the resolved value
9
+ *
10
+ * A leaf holds what the setting's reader accepts, which is not always
11
+ * what `RafaConfig` resolves it to. A map (`routing`, `tiers.skills`,
12
+ * `tiers.agents`, `logger.modules`) is a plain object here and a
13
+ * `ReadonlyMap` there; `loop.settingSources` is the comma-separated
14
+ * string the file writes (`project,local`) and a list there; an item of
15
+ * `prerequisites.required` or `modules` names its kind by its key
16
+ * (`{ tool: 'bun' }`, `{ npm: 'rafa-board' }`) where the resolved item
17
+ * carries `kind` and `name`; and a setting whose default is null
18
+ * (`pr.base`, `hub.url`) takes no null, since no reader accepts one.
19
+ *
20
+ * ## Who declares what
21
+ *
22
+ * This module declares core's own top-level keys, the keys of
23
+ * `packages/rafa/src/core/config/core-section.ts`, and composes {@link ConfigShape}
24
+ * from them and the interface each of the thirteen section files
25
+ * (`src/config-schema-*.ts`) exports for the keys it writes: `HubShape`
26
+ * for `hub`, `ReleaseShape` for `pr` and `release`, and so on, each
27
+ * extended by {@link ConfigShape}. A namespace two packages share is a
28
+ * named interface here holding core's keys and extending the part each
29
+ * section exports as an interface of its own: {@link LoopShape} extends
30
+ * `LoopRetriesShape`, `LoopContinueShape` and `WrapUpShape`,
31
+ * {@link BoardProjectShape} extends `BoardProjectLimitsShape`, and
32
+ * {@link DangerousShape} extends `ReleaseDangerousShape`.
33
+ *
34
+ * The composition is written out, not merged into this file by a
35
+ * section's `declare module`, so the declaration emitted for this file
36
+ * imports each section's emitted declaration and a reader of the
37
+ * `./config` subpath's `.d.ts` files alone sees every key.
38
+ * `shape.test.ts` emits the declarations in memory over
39
+ * `src/config/index.ts` and reads `ConfigShape['hub']['url']` as
40
+ * `string` from them.
41
+ *
42
+ * `shape.test.ts` reads every leaf back as a setting's key and every
43
+ * setting's key as a leaf, so a key added to a section without its leaf
44
+ * here, or the other way round, fails there.
45
+ *
46
+ * Every type is `import type`, so this module loads nothing.
47
+ */
48
+ import type { BoardProjectLimitsShape } from '../config-schema-board-project.js';
49
+ import type { BugsShape } from '../config-schema-bugs.js';
50
+ import type { ErrorsShape } from '../config-schema-errors.js';
51
+ import type { FeaturesShape } from '../config-schema-features.js';
52
+ import type { HubShape } from '../config-schema-hub.js';
53
+ import type { IssuesShape } from '../config-schema-issues.js';
54
+ import type { LoggerShape } from '../config-schema-logger.js';
55
+ import type { LoopContinueShape } from '../config-schema-loop-continue.js';
56
+ import type { LoopRetriesShape } from '../config-schema-loop-retries.js';
57
+ import type { ReleaseDangerousShape, ReleaseShape } from '../config-schema-release.js';
58
+ import type { TestsShape } from '../config-schema-tests.js';
59
+ import type { TriageShape } from '../config-schema-triage.js';
60
+ import type { WrapUpShape } from '../config-schema-wrap-up.js';
61
+ import type { ModuleSourceKind, PrerequisiteKind } from '@open-tomato/rafa/core/config';
62
+ import type { BoardRelationshipMode, ClaimsAhead, ClaimsStaleAfter, ConfigVersion, DuplicatesLevel, InjectMode, LessonSwitch, OutputMode, RouteTarget, SkillResolverName, StoreBackend, SyncStrategy, TierPin, TierSwitch } from '@open-tomato/rafa/core/config/sections';
63
+ /**
64
+ * An item keyed by its kind: one of `K` as its key, naming the item.
65
+ * `KindKeyed<'tool' | 'env'>` is `{ tool: string } | { env: string }`.
66
+ */
67
+ type KindKeyed<K extends string> = {
68
+ readonly [P in K]: {
69
+ readonly [Q in P]: string;
70
+ };
71
+ }[K];
72
+ /** One `prerequisites.required` item as a file writes it: `{ tool: 'bun', probe: 'bun --version' }`. */
73
+ export type PrerequisiteFileItem = KindKeyed<PrerequisiteKind> & {
74
+ /** The command that proves the item; left out or null to check presence alone. */
75
+ readonly probe?: string | null;
76
+ };
77
+ /** One `prerequisites.optional` item as a file writes it: a required item's keys and `reason`. */
78
+ export type OptionalPrerequisiteFileItem = PrerequisiteFileItem & {
79
+ /** Why the item helps, for the line naming it missing. */
80
+ readonly reason?: string | null;
81
+ };
82
+ /**
83
+ * One `modules` entry as a file writes it: `{ npm: 'rafa-board' }`,
84
+ * `{ path: '../board' }`, or `{ github: 'owner/repo', ref: 'v1' }`.
85
+ */
86
+ export type ModuleFileItem = KindKeyed<Exclude<ModuleSourceKind, 'github'>> | {
87
+ /** The `owner/repo` the module is cloned from. */
88
+ readonly github: string;
89
+ /** The git ref to check out; left out or null for the default branch. */
90
+ readonly ref?: string | null;
91
+ };
92
+ /**
93
+ * The `loop` namespace: core's two keys, and the keys the
94
+ * `loop-retries`, `loop-continue` and `wrap-up` sections write.
95
+ */
96
+ export interface LoopShape extends LoopRetriesShape, LoopContinueShape, WrapUpShape {
97
+ /** `loop.settingSources`: a comma-separated subset of `user`, `project`, `local`. */
98
+ readonly settingSources: string;
99
+ /** `loop.worktreeDir`: where the loop's worktrees are made. */
100
+ readonly worktreeDir: string;
101
+ }
102
+ /** The `board.project` namespace: core's two keys and the `board-project` section's limits. */
103
+ export interface BoardProjectShape extends BoardProjectLimitsShape {
104
+ /** `board.project.template`: the project board copied for a new board. */
105
+ readonly template: string;
106
+ /** `board.project.number`: the project board this repository's issues go on. */
107
+ readonly number: number;
108
+ }
109
+ /** The `board` namespace, core's, with the shared {@link BoardProjectShape} under `project`. */
110
+ export interface BoardShape {
111
+ /** `board.trustedAuthors`: the GitHub logins whose board items are read without a prompt. */
112
+ readonly trustedAuthors: readonly string[];
113
+ /** `board.relationships`: how a parent and its children are linked. */
114
+ readonly relationships: BoardRelationshipMode;
115
+ /** The `board.project` keys. */
116
+ readonly project: BoardProjectShape;
117
+ }
118
+ /**
119
+ * The `dangerous` namespace: each key a person's consent to a step rafa
120
+ * otherwise refuses. Core's two, and the one the `release` section writes.
121
+ */
122
+ export interface DangerousShape extends ReleaseDangerousShape {
123
+ /** `dangerous.acceptStaleRefs`. */
124
+ readonly acceptStaleRefs: boolean;
125
+ /** `dangerous.selfUpdateDuringLoop`. */
126
+ readonly selfUpdateDuringLoop: boolean;
127
+ }
128
+ /** The nested file shape: core's keys, and each section's; see the module note. */
129
+ export interface ConfigShape extends BugsShape, ErrorsShape, FeaturesShape, HubShape, IssuesShape, LoggerShape, ReleaseShape, TestsShape, TriageShape {
130
+ /** `version`: the config format's version. */
131
+ readonly version: ConfigVersion;
132
+ /** `store`: the effort store's backend. */
133
+ readonly store: StoreBackend;
134
+ /** The `effort` keys. */
135
+ readonly effort: {
136
+ readonly busyTimeoutMs: number;
137
+ readonly sync: SyncStrategy;
138
+ };
139
+ /** The `plan` keys. */
140
+ readonly plan: {
141
+ readonly inject: InjectMode;
142
+ readonly dir: string;
143
+ };
144
+ /** The `specs` keys. */
145
+ readonly specs: {
146
+ readonly dir: string;
147
+ };
148
+ /** The `tracker` keys. */
149
+ readonly tracker: {
150
+ readonly default: string;
151
+ readonly fallback: readonly string[];
152
+ };
153
+ /** The `learning` keys. */
154
+ readonly learning: {
155
+ readonly adapter: string;
156
+ readonly bless: {
157
+ readonly minConfidence: number;
158
+ };
159
+ readonly promote: {
160
+ readonly after: number;
161
+ readonly minConfidence: number;
162
+ };
163
+ };
164
+ /** The `output` keys. */
165
+ readonly output: {
166
+ readonly mode: OutputMode;
167
+ };
168
+ /** The `prerequisites` keys. */
169
+ readonly prerequisites: {
170
+ readonly required: readonly PrerequisiteFileItem[];
171
+ readonly optional: readonly OptionalPrerequisiteFileItem[];
172
+ };
173
+ /** The `tracking` keys. */
174
+ readonly tracking: {
175
+ readonly specs: boolean;
176
+ readonly plans: boolean;
177
+ readonly all: boolean;
178
+ };
179
+ /** `modules`: where each module is installed from. */
180
+ readonly modules: readonly ModuleFileItem[];
181
+ /** `allowList`. */
182
+ readonly allowList: readonly string[];
183
+ /** The `loop` keys. */
184
+ readonly loop: LoopShape;
185
+ /** The `board` keys. */
186
+ readonly board: BoardShape;
187
+ /** The `roadmap` keys. */
188
+ readonly roadmap: {
189
+ readonly issue: number;
190
+ };
191
+ /** The `claims` keys. */
192
+ readonly claims: {
193
+ readonly staleAfter: ClaimsStaleAfter;
194
+ readonly ahead: ClaimsAhead;
195
+ };
196
+ /** The `cleanup` keys. */
197
+ readonly cleanup: {
198
+ readonly staleDays: number;
199
+ readonly worktreeIdleDays: number;
200
+ readonly keep: readonly string[];
201
+ };
202
+ /** The `dangerous` keys. */
203
+ readonly dangerous: DangerousShape;
204
+ /** The `status` keys. */
205
+ readonly status: {
206
+ readonly notice: boolean;
207
+ };
208
+ /** The `tiers` keys, each map a name to `false` or a tier. */
209
+ readonly tiers: {
210
+ readonly rafa: TierSwitch;
211
+ readonly skills: Readonly<Record<string, TierPin>>;
212
+ readonly agents: Readonly<Record<string, TierPin>>;
213
+ };
214
+ /** `routing`: a task shape to an agent, or `false`. */
215
+ readonly routing: Readonly<Record<string, RouteTarget>>;
216
+ /** The `task` keys. */
217
+ readonly task: {
218
+ readonly skills: SkillResolverName;
219
+ readonly lessons: LessonSwitch;
220
+ };
221
+ /** The `merge` keys. */
222
+ readonly merge: {
223
+ /** `merge.duplicates`: how two entries of one file setting one key are reported. */
224
+ readonly duplicates: DuplicatesLevel;
225
+ };
226
+ /** The `naming` keys. */
227
+ readonly naming: {
228
+ /** `naming.branch`: the template the branch `loop start` creates is named from, holding `{stub}` once. */
229
+ readonly branch: string;
230
+ };
231
+ }
232
+ export {};
@@ -0,0 +1,127 @@
1
+ /**
2
+ * The registry: the fourteen sections of the config schema, handed to
3
+ * core when {@link registerCoreConfigSections} is called, and the merged schema read off
4
+ * them, {@link SETTINGS}, {@link CONFIG_DEFAULTS}, {@link SETTING_NAMES},
5
+ * {@link SETTING_BY_KEY}, {@link SECTIONS} and {@link knownKeysAbove}.
6
+ *
7
+ * Core declares the section contract (`packages/rafa/src/core/config/section.ts`) and
8
+ * names no section. This module, outside `packages/rafa/src/core/`, is the one place
9
+ * the fourteen are listed, {@link CONFIG_SECTIONS}: core's own
10
+ * (`CORE_SECTION`) and the thirteen files `src/config-schema-*.ts` that
11
+ * each export one.
12
+ *
13
+ * Importing it registers nothing. {@link registerCoreConfigSections}
14
+ * calls `registerConfigSections` once, with that list cut into the runs
15
+ * {@link SETTINGS} holds (see the order below), so `activeSettings()`
16
+ * and `activeDefaults()` answer every setting; a registration core
17
+ * refuses throws from the call, naming what it refused. The root is
18
+ * called, never imported for its effect: under `"sideEffects": false`
19
+ * in a manifest, `bun build` drops an import kept for its effect alone.
20
+ * The root manifest declares no such field today, since bun 1.3.14's
21
+ * split build breaks under it (#1213).
22
+ * `src/rafa.ts` and `src/index.ts` call it as they load, after their
23
+ * imports, ahead of `registerCoreAdapters` and before anything that
24
+ * loads a config; core never imports this module. Until something calls
25
+ * it, `loadConfig` refuses, naming this module. `bun test` calls it once
26
+ * for the test process, from `src/tests/preload.ts`; a child process a
27
+ * test spawns runs no preload, and calls the root itself. A second call
28
+ * finds every setting registered already and registers nothing.
29
+ *
30
+ * The call also sets core's load hook (`setConfigLoadHook` in
31
+ * `packages/rafa/src/core/config/section.ts`) to {@link handConfigToLogger}, so every
32
+ * config `loadConfig` resolves hands the logger its `logger` settings
33
+ * without core importing the logger's section file.
34
+ *
35
+ * ## The order
36
+ *
37
+ * {@link SETTINGS} keeps the order the schema has always reported
38
+ * problems in, which is not the order of the list: core's settings are
39
+ * taken in runs, and each section's settings are spread whole between
40
+ * two of them, so `hub.url` follows `effort.sync` and the `board.project`
41
+ * limits follow `board.project.number`. The `release` section is spread
42
+ * in three parts, its `pr`, `release` and `dangerous.` keys, each where
43
+ * its keys have always stood.
44
+ *
45
+ * Core reads every setting in the order it was registered: a layer, a
46
+ * resolution, and the keys a warning about an unknown key lists. So the
47
+ * sections are registered cut into the runs {@link SETTINGS} holds them
48
+ * in (`inSettingOrder`), each cut under its section's package and a
49
+ * section's checks on its first cut, and core's registry holds every
50
+ * setting in this order. Registering the list whole would put core's
51
+ * forty-two first, and the warning recorded in
52
+ * `src/tests/fixtures/config-parity/` would list `hub` after `task`.
53
+ * `config-registry.test.ts` holds that the registry holds the same
54
+ * settings, in the same order, as the same specs, and the same defaults,
55
+ * as the same values.
56
+ *
57
+ * ## The closed set
58
+ *
59
+ * {@link SETTINGS} is a mapped record over `ConfigSetting` built from
60
+ * each section file's typed settings, so a field added to `RafaConfig`
61
+ * without a spec in some section does not compile. The indexes are all
62
+ * read off it. Keys are looked up in a `Map`, never with `in` or an
63
+ * object index: `Bun.YAML.parse` returns a key spelled `constructor` or
64
+ * `__proto__` as an ordinary own key, and an object lookup would match
65
+ * it against `Object.prototype` instead.
66
+ *
67
+ * ## Beside core
68
+ *
69
+ * This module is the one place the six names are built: the core barrel
70
+ * `packages/rafa/src/core/config/index.ts` exports none of them, and a file outside
71
+ * `packages/rafa/src/core/` imports them from here. Core reads the registered
72
+ * settings and defaults through `activeSettings()` and
73
+ * `activeDefaults()`, and the key indexes through `activeSettingByKey()`,
74
+ * `activeSectionPaths()` and `activeKnownKeysAbove()`, all in
75
+ * `packages/rafa/src/core/config/section.ts`. Those follow registration order, which
76
+ * is the order here, so they answer what {@link SETTING_BY_KEY},
77
+ * {@link SECTIONS} and {@link knownKeysAbove} answer.
78
+ * `src/index.ts` publishes this module's {@link CONFIG_DEFAULTS}.
79
+ */
80
+ import type { ConfigSection, ConfigSetting, RafaConfig, SettingSpec } from '@open-tomato/rafa/core/config';
81
+ /** The fourteen sections, core's first, in the order they are registered. */
82
+ export declare const CONFIG_SECTIONS: readonly ConfigSection[];
83
+ /**
84
+ * The hook `loadConfig` calls with every config it resolves: it hands
85
+ * the logger its `logger` settings, read through the logger section's
86
+ * `loggerSettingsOf`. Set by {@link registerCoreConfigSections}, beside
87
+ * the registration.
88
+ */
89
+ export declare function handConfigToLogger(config: Readonly<RafaConfig>): void;
90
+ /** What every setting resolves to when no layer names it. */
91
+ export declare const CONFIG_DEFAULTS: Readonly<RafaConfig>;
92
+ /**
93
+ * Every setting, by name, in the order problems are reported.
94
+ *
95
+ * A mapped record rather than a list so the set is closed: a field
96
+ * added to `RafaConfig` without an entry here does not compile.
97
+ */
98
+ export declare const SETTINGS: {
99
+ readonly [K in ConfigSetting]: SettingSpec<K>;
100
+ };
101
+ /** Every setting name, read off the closed record above. */
102
+ export declare const SETTING_NAMES: readonly ConfigSetting[];
103
+ /**
104
+ * Registers {@link CONFIG_SECTIONS} with core, cut into the runs
105
+ * {@link SETTINGS} holds them in, and sets core's load hook to
106
+ * {@link handConfigToLogger}.
107
+ *
108
+ * When core's registry holds every setting already, each as the same
109
+ * spec, it registers nothing and leaves the load hook as it is, so the
110
+ * preload and an entry may both call it in one process. Throws what
111
+ * `registerConfigSections` throws on a section core refuses, such as a
112
+ * setting another package registered first, leaving the registry and
113
+ * the load hook as they were.
114
+ */
115
+ export declare function registerCoreConfigSections(): void;
116
+ /** Setting names by the dotted key the file spells them with. */
117
+ export declare const SETTING_BY_KEY: ReadonlyMap<string, ConfigSetting>;
118
+ /** Every dotted prefix a setting sits under: the sections a file opens. */
119
+ export declare const SECTIONS: ReadonlySet<string>;
120
+ /**
121
+ * The nearest path above `key` with known keys, and those keys. An
122
+ * item path such as `modules[0]` looks up `modules[]`.
123
+ *
124
+ * @param key - A dotted key a file spelled, `modules[0].kind` included.
125
+ * @returns The path the keys sit under, `''` for the top, and the keys.
126
+ */
127
+ export declare function knownKeysAbove(key: string): [string, readonly string[]];