@open-tomato/rafa 0.45.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 (140) hide show
  1. package/README.md +255 -23
  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 +101 -18
  14. package/dist/cli.js +74726 -62960
  15. package/dist/config/entry.d.ts +119 -0
  16. package/dist/config/index.d.ts +36 -0
  17. package/dist/config/index.js +51 -0
  18. package/dist/config/shape.d.ts +232 -0
  19. package/dist/config-registry.d.ts +127 -0
  20. package/dist/config-schema-board-project.d.ts +157 -0
  21. package/dist/config-schema-bugs.d.ts +71 -0
  22. package/dist/config-schema-errors.d.ts +54 -0
  23. package/dist/config-schema-features.d.ts +64 -0
  24. package/dist/config-schema-hub.d.ts +150 -0
  25. package/dist/config-schema-issues.d.ts +95 -0
  26. package/dist/config-schema-logger.d.ts +91 -0
  27. package/dist/config-schema-loop-continue.d.ts +122 -0
  28. package/dist/config-schema-loop-retries.d.ts +94 -0
  29. package/dist/config-schema-release.d.ts +307 -0
  30. package/dist/config-schema-tests.d.ts +170 -0
  31. package/dist/config-schema-triage.d.ts +142 -0
  32. package/dist/config-schema-wrap-up.d.ts +96 -0
  33. package/dist/core/command/command.d.ts +228 -0
  34. package/dist/core/command/confirm.d.ts +67 -0
  35. package/dist/core/command/index.d.ts +112 -0
  36. package/dist/core/command/lazy.d.ts +54 -0
  37. package/dist/core/command/registry-types.d.ts +96 -0
  38. package/dist/core/command/running.d.ts +96 -0
  39. package/dist/core/command/spends.d.ts +39 -0
  40. package/dist/core/command/types.d.ts +92 -0
  41. package/dist/core/command/version.d.ts +4 -0
  42. package/dist/core/config/branch-template.d.ts +20 -0
  43. package/dist/core/config/config-items.d.ts +86 -0
  44. package/dist/core/config/config-load.d.ts +47 -0
  45. package/dist/core/config/config-origins.d.ts +57 -0
  46. package/dist/core/config/config-readers.d.ts +167 -0
  47. package/dist/core/config/config-schema.d.ts +207 -0
  48. package/dist/core/config/config-sections.d.ts +493 -0
  49. package/dist/core/config/config.d.ts +320 -0
  50. package/dist/core/config/core-section.d.ts +39 -0
  51. package/dist/core/config/dangerous.d.ts +58 -0
  52. package/dist/core/config/default-routing.d.ts +16 -0
  53. package/dist/core/config/index.d.ts +141 -0
  54. package/dist/core/config/scope.d.ts +42 -0
  55. package/dist/core/config/section.d.ts +206 -0
  56. package/dist/core/config/sections.d.ts +45 -0
  57. package/dist/core/config/standard-schema.d.ts +27 -0
  58. package/dist/core/git/commit.d.ts +232 -0
  59. package/dist/core/git/gh-runner.d.ts +24 -0
  60. package/dist/core/git/git.d.ts +22 -0
  61. package/dist/core/git/index.d.ts +85 -0
  62. package/dist/core/loop/claude.d.ts +388 -0
  63. package/dist/core/loop/hop-record.d.ts +52 -0
  64. package/dist/core/loop/index.d.ts +179 -0
  65. package/dist/core/loop/session-env.d.ts +20 -0
  66. package/dist/core/loop/session-record-parse.d.ts +63 -0
  67. package/dist/core/loop/sessions.d.ts +408 -0
  68. package/dist/core/loop/suite-failure.d.ts +25 -0
  69. package/dist/core/output/active.d.ts +100 -0
  70. package/dist/core/output/stream.d.ts +20 -0
  71. package/dist/core/output/text.d.ts +55 -0
  72. package/dist/core/plan/block-reader.d.ts +46 -0
  73. package/dist/core/plan/blocks.d.ts +139 -0
  74. package/dist/core/plan/declaration.d.ts +366 -0
  75. package/dist/core/plan/plan-stamp.d.ts +75 -0
  76. package/dist/core/runtime/identity.d.ts +21 -0
  77. package/dist/core/runtime/index.d.ts +46 -0
  78. package/dist/effort/store/bring-forward.d.ts +131 -0
  79. package/dist/effort/store/check-rows.d.ts +31 -0
  80. package/dist/effort/store/commit-stats.d.ts +42 -0
  81. package/dist/effort/store/copy.d.ts +35 -0
  82. package/dist/effort/store/development-build.d.ts +105 -0
  83. package/dist/effort/store/effort-levels.d.ts +13 -0
  84. package/dist/effort/store/findings.d.ts +214 -0
  85. package/dist/effort/store/fix-schema.d.ts +184 -0
  86. package/dist/effort/store/index.js +10 -7
  87. package/dist/effort/store/location.d.ts +44 -0
  88. package/dist/effort/store/merge-commit-gaps.d.ts +68 -0
  89. package/dist/effort/store/merge-conflicts.d.ts +91 -0
  90. package/dist/effort/store/merge-rules.d.ts +82 -0
  91. package/dist/effort/store/merge-store.d.ts +211 -0
  92. package/dist/effort/store/merge-union.d.ts +92 -0
  93. package/dist/effort/store/migrate.d.ts +146 -0
  94. package/dist/effort/store/migrations.d.ts +92 -0
  95. package/dist/effort/store/ndjson-files.d.ts +114 -0
  96. package/dist/effort/store/origins.d.ts +116 -0
  97. package/dist/effort/store/plan-stubs.d.ts +79 -0
  98. package/dist/effort/store/rebuild-aside.d.ts +172 -0
  99. package/dist/effort/store/schema-plan.d.ts +102 -0
  100. package/dist/effort/store/session-row-types.d.ts +64 -0
  101. package/dist/effort/store/settings.d.ts +13 -0
  102. package/dist/effort/store/sqlite.d.ts +340 -0
  103. package/dist/effort/store/store-generation.d.ts +17 -0
  104. package/dist/effort/store/store-identity.d.ts +220 -0
  105. package/dist/effort/store/store-meta.d.ts +305 -0
  106. package/dist/effort/store/store-replaced.d.ts +72 -0
  107. package/dist/effort/store/types.d.ts +223 -0
  108. package/dist/errors/codes.d.ts +56 -0
  109. package/dist/errors/rafa-codes.d.ts +36 -0
  110. package/dist/index-2a7nb3an.js +125 -0
  111. package/dist/{index-r28fzsvc.js → index-39kbcw68.js} +350 -165
  112. package/dist/{index-nv34ptht.js → index-77ajfffn.js} +14 -9
  113. package/dist/index-cy98y87p.js +2597 -0
  114. package/dist/index-gqz4jn6j.js +13447 -0
  115. package/dist/index-gvek4r8m.js +710 -0
  116. package/dist/index-j4k2vdz3.js +1125 -0
  117. package/dist/index-jh1r4kcn.js +1067 -0
  118. package/dist/{index-mgh2s9bj.js → index-ykggr043.js} +58 -455
  119. package/dist/index-z1w83f81.js +4 -0
  120. package/dist/index.js +14715 -21516
  121. package/dist/learning/index.js +5 -6
  122. package/dist/plan/index.js +12 -11
  123. package/dist/plan-prompt.md +3 -1
  124. package/dist/ports/index.d.ts +732 -0
  125. package/dist/ports/learning.d.ts +101 -0
  126. package/dist/ports/log-level.d.ts +13 -0
  127. package/dist/ports/spec-review.d.ts +66 -0
  128. package/dist/pr/checks.d.ts +133 -0
  129. package/dist/pr/types.d.ts +422 -0
  130. package/dist/ready-4f8edezt.js +2016 -0
  131. package/dist/release-templates/release-bot-fragment.yml +153 -0
  132. package/dist/release-templates/release-publish.yml +110 -0
  133. package/dist/release-templates/release-settle.yml +122 -0
  134. package/dist/release-templates/release-tag.yml +102 -0
  135. package/dist/report/parse.d.ts +415 -0
  136. package/dist/schema/project-id.d.ts +79 -0
  137. package/dist/schema/tiers.d.ts +107 -0
  138. package/package.json +41 -3
  139. package/dist/index-hf2k497d.js +0 -16
  140. package/dist/index-nsr78ct2.js +0 -8219
@@ -0,0 +1,206 @@
1
+ /**
2
+ * The section contract: how a slice of the config schema is handed to
3
+ * core, and the registry core reads the merged slices from.
4
+ *
5
+ * A {@link ConfigSection} is one package's part of the schema: its
6
+ * `settings` (each setting's file key, reader and command-line flag, as
7
+ * a partial of the record of every setting, {@link SettingsRecord}), its
8
+ * `defaults` (a partial of {@link RafaConfig}), and the cross-key
9
+ * `checks` run over the resolved config. {@link registerConfigSections}
10
+ * merges sections into the active registry, which {@link activeSettings},
11
+ * {@link activeDefaults} and {@link activeChecks} answer, and the key
12
+ * indexes below are read off. Core names no section here: the list of
13
+ * sections lives outside `packages/rafa/src/core/`, in `src/config-registry.ts`, the
14
+ * module that calls {@link registerConfigSections}.
15
+ *
16
+ * This file imports types alone, so it loads first in any order and can
17
+ * be imported by value from the loader and from every section file
18
+ * without closing a runtime cycle.
19
+ *
20
+ * ## The refusals
21
+ *
22
+ * A registration that breaks one of four rules throws a
23
+ * {@link ConfigSectionError} listing every problem it found, one
24
+ * sentence each, and leaves the active registry as it was:
25
+ *
26
+ * - A setting name registered by one section and again by another, in
27
+ * this call or an earlier one. The sentence names both packages, the
28
+ * one holding the name first.
29
+ * - A file key defined by one section and again by another under a
30
+ * different setting name. Two settings read off one key would
31
+ * answer one value under two names, so the sentence names both
32
+ * packages and both setting names, the one holding the key first.
33
+ * - A file key opening with `dangerous.` defined by one section and
34
+ * again by another under the same setting name. A `dangerous.*` key
35
+ * is a person's consent to a risk, so a second package defining it
36
+ * could widen what that consent was given for; the sentence names
37
+ * both packages, and the setting-name sentence is read beside it.
38
+ * Any other key redefined under the same name reads the setting-name
39
+ * sentence alone.
40
+ * - A {@link RafaConfig} field no section defines: a default given for
41
+ * a field no registered section has a setting for, or a setting no
42
+ * registered section gives a default for. The sentence names the
43
+ * package that gave the half it has. Types are erased at runtime, so
44
+ * a field declared on {@link RafaConfig} that no section mentions at
45
+ * all is out of this module's reach; the module that lists the
46
+ * sections is where a complete set is held.
47
+ *
48
+ * The completeness rule reads the registry as it would stand after the
49
+ * call, so a section whose setting and default come in two calls is
50
+ * refused at the first. A section's package must be a non-empty string,
51
+ * since every refusal names one.
52
+ *
53
+ * The key rules compare one section with the sections before it, in
54
+ * this call or an earlier one; two setting names one section gives the
55
+ * same key are not compared with each other.
56
+ *
57
+ * ## A registry is a value
58
+ *
59
+ * {@link mergeConfigSections} answers a new {@link ConfigSectionRegistry}
60
+ * and leaves the one it was handed unchanged; each section is copied and
61
+ * frozen as it is accepted, so editing a section object afterwards
62
+ * changes nothing registered. The active registry is the one
63
+ * module-level value: {@link registerConfigSections} replaces it with a
64
+ * merge and answers the one it replaced, and
65
+ * {@link restoreConfigSections} puts one back. Bun runs every test file
66
+ * in one process, so a case that registers puts the previous registry
67
+ * back in a `finally`, or every file bun runs later reads its sections.
68
+ * {@link EMPTY_CONFIG_REGISTRY} is the registry before any registration.
69
+ *
70
+ * ## The key indexes
71
+ *
72
+ * `config.ts` sorts a file's keys through three indexes of the active
73
+ * registry's settings: {@link activeSettingByKey}, the setting each
74
+ * dotted file key names; {@link activeSectionPaths}, every dotted prefix
75
+ * a setting sits under, which are the sections a file may open; and
76
+ * {@link activeKnownKeysAbove}, the keys a warning about an unknown key
77
+ * lists. Each is built on first read and kept per registry, so a
78
+ * registration or a restore is read at once and a registry is indexed
79
+ * once. Keys are looked up in a `Map` and a `Set`, never with `in` or an
80
+ * object index: `Bun.YAML.parse` returns a key spelled `constructor`,
81
+ * `toString` or `__proto__` as an ordinary own key, and an object lookup
82
+ * would match it against `Object.prototype` instead.
83
+ *
84
+ * The indexes follow registration order: the keys under a path are
85
+ * listed in the order their settings were registered. The registry
86
+ * registers its sections cut into the order the schema has always
87
+ * reported problems in, so a warning lists the keys it always listed;
88
+ * `src/config-registry.test.ts` holds the indexes to the registry's own.
89
+ *
90
+ * ## The load hook
91
+ *
92
+ * A setting core resolves can be read by a module outside `packages/rafa/src/core/`
93
+ * that core must not import: the logger's settings are read through
94
+ * `loggerSettingsOf` in `src/config-schema-logger.ts`. So the module that
95
+ * lists the sections also hands core one {@link ConfigLoadHook} with
96
+ * {@link setConfigLoadHook}, and `loadConfig` (`config-load.ts`) calls
97
+ * {@link activeConfigLoadHook} with every config it resolves, before it
98
+ * prints the config's warnings. The hook is a module-level value of its
99
+ * own, beside the registry rather than in it: restoring a registry
100
+ * leaves the hook as it was, and a case that sets one puts the previous
101
+ * hook back in a `finally`, as a case that registers does.
102
+ */
103
+ import type { ConfigSetting, RafaConfig, SettingSpec } from './config-schema.js';
104
+ import type { ConfigSource } from './config.js';
105
+ /** Every setting's spec, by name: the record a section hands a part of. */
106
+ export type SettingsRecord = {
107
+ readonly [K in ConfigSetting]: SettingSpec<K>;
108
+ };
109
+ /** What a section's check reads: the resolved values, their layers and the files read. */
110
+ export interface ConfigCheckInput {
111
+ /** The value each setting resolved to. */
112
+ readonly config: Readonly<RafaConfig>;
113
+ /** The layer that answered each setting. */
114
+ readonly sources: Readonly<Record<ConfigSetting, ConfigSource>>;
115
+ /** The project's file consulted, or null when there was none. */
116
+ readonly path: string | null;
117
+ /** The user scope's file consulted, or null when there was none. */
118
+ readonly userPath: string | null;
119
+ }
120
+ /**
121
+ * A cross-key refusal: the problems the resolved config holds, one
122
+ * sentence each, or an empty list when it holds none.
123
+ */
124
+ export type ConfigCheck = (input: ConfigCheckInput) => readonly string[];
125
+ /** One package's slice of the config schema. */
126
+ export interface ConfigSection {
127
+ /** The package the section belongs to, named by every refusal. */
128
+ readonly package: string;
129
+ /** The specs of the settings the section defines. */
130
+ readonly settings: Partial<SettingsRecord>;
131
+ /** The default of each setting the section defines. */
132
+ readonly defaults: Partial<RafaConfig>;
133
+ /** The cross-key refusals run over the resolved config. */
134
+ readonly checks?: readonly ConfigCheck[];
135
+ }
136
+ /** The sections merged so far, and what core reads off them. */
137
+ export interface ConfigSectionRegistry {
138
+ /** Every section accepted, copied and frozen, in registration order. */
139
+ readonly sections: readonly ConfigSection[];
140
+ /** Every setting's spec, in registration order. */
141
+ readonly settings: Readonly<Partial<SettingsRecord>>;
142
+ /** Every setting's default. */
143
+ readonly defaults: Readonly<Partial<RafaConfig>>;
144
+ /** Every section's checks, in registration order. */
145
+ readonly checks: readonly ConfigCheck[];
146
+ }
147
+ /**
148
+ * A registration refused: a setting name defined twice, a file key two
149
+ * sections define under two setting names or a `dangerous.` key under
150
+ * one, a field no section defines, or a section with no package name.
151
+ */
152
+ export declare class ConfigSectionError extends Error {
153
+ /** Every problem found, one sentence each. */
154
+ readonly problems: readonly string[];
155
+ constructor(problems: readonly string[]);
156
+ }
157
+ /** The registry before any registration: no section, setting, default or check. */
158
+ export declare const EMPTY_CONFIG_REGISTRY: ConfigSectionRegistry;
159
+ /**
160
+ * A new registry holding `registry`'s sections and then `sections`, or a
161
+ * {@link ConfigSectionError} listing every problem found; see the module
162
+ * note. `registry` is left unchanged either way.
163
+ */
164
+ export declare function mergeConfigSections(registry: ConfigSectionRegistry, sections: readonly ConfigSection[]): ConfigSectionRegistry;
165
+ /**
166
+ * Merges `sections` into the active registry, or throws a
167
+ * {@link ConfigSectionError} and leaves it unchanged. Answers the
168
+ * registry it replaced, for {@link restoreConfigSections}.
169
+ */
170
+ export declare function registerConfigSections(sections: readonly ConfigSection[]): ConfigSectionRegistry;
171
+ /** Makes `registry` the active one: what {@link registerConfigSections} answered, or {@link EMPTY_CONFIG_REGISTRY}. */
172
+ export declare function restoreConfigSections(registry: ConfigSectionRegistry): void;
173
+ /** Every registered section, in registration order. */
174
+ export declare function activeSections(): readonly ConfigSection[];
175
+ /** Every registered setting's spec, in registration order. */
176
+ export declare function activeSettings(): Readonly<Partial<SettingsRecord>>;
177
+ /** Every registered setting's default. */
178
+ export declare function activeDefaults(): Readonly<Partial<RafaConfig>>;
179
+ /** Every registered section's checks, in registration order. */
180
+ export declare function activeChecks(): readonly ConfigCheck[];
181
+ /** Every registered setting's name, by the dotted key a file spells it with. */
182
+ export declare function activeSettingByKey(): ReadonlyMap<string, ConfigSetting>;
183
+ /** Every dotted prefix a registered setting sits under: the sections a file opens. */
184
+ export declare function activeSectionPaths(): ReadonlySet<string>;
185
+ /**
186
+ * The nearest path above `key` with registered keys, and those keys, in
187
+ * registration order. An item path such as `modules[0]` looks up the
188
+ * item keys of `modules`.
189
+ *
190
+ * @param key - A dotted key a file spelled, `modules[0].kind` included.
191
+ * @returns The path the keys sit under, `''` for the top, and the keys.
192
+ */
193
+ export declare function activeKnownKeysAbove(key: string): [string, readonly string[]];
194
+ /**
195
+ * What `loadConfig` hands every config it resolves to, before printing
196
+ * its warnings: the reading of settings a module outside `packages/rafa/src/core/`
197
+ * acts on. See the module note.
198
+ */
199
+ export type ConfigLoadHook = (config: Readonly<RafaConfig>) => void;
200
+ /**
201
+ * Makes `hook` the one `loadConfig` calls, or clears it with null.
202
+ * Answers the hook it replaced, for a caller to put back.
203
+ */
204
+ export declare function setConfigLoadHook(hook: ConfigLoadHook | null): ConfigLoadHook | null;
205
+ /** The hook `loadConfig` calls with every config it resolves, or null when none is set. */
206
+ export declare function activeConfigLoadHook(): ConfigLoadHook | null;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * The barrel over the config's value readers: every name
3
+ * `config-sections.ts`, `config-readers.ts` and `branch-template.ts`
4
+ * export, and nothing else.
5
+ *
6
+ * A file outside `packages/rafa/src/core/` imports this file and never the three behind
7
+ * it (`scripts/survey/core-barrels.ts` measures that, and
8
+ * `src/tests/core-barrels.sweep.test.ts` holds it against the tree). A
9
+ * file inside `packages/rafa/src/core/` imports the three directly and never this file.
10
+ *
11
+ * ## Why the pair has a barrel of its own
12
+ *
13
+ * `packages/rafa/src/core/config/` has three barrels, all listed under `CORE_BARRELS`
14
+ * in `scripts/survey/core-moves.ts`. This one holds the leaf pair: the
15
+ * two files import each other one way (`config-readers.ts` reads
16
+ * `config-sections.ts`), `node:path`, and four modules that import none
17
+ * of the config back. The schema's section files (`src/config-schema-*.ts`)
18
+ * import the pair by value. While `config-merged.ts` imported them by
19
+ * value in turn, one barrel over the pair and the schema would have made
20
+ * every section file import a barrel that imports it back: a runtime
21
+ * cycle that fails as a `ReferenceError` at load, in one import order
22
+ * only. That file is retired, and measured since, no value import of a
23
+ * file behind `index.ts` reaches a section file, so that cycle is no
24
+ * longer what keeps the two barrels apart; they stay as the move left
25
+ * them, a name with one barrel to be learned from.
26
+ *
27
+ * `branch-template.ts` joined the pair with the readers of a branch name
28
+ * through the `naming.branch` template, `branchGlob` and `stubOfBranch`.
29
+ * It imports `config-readers.ts` alone, so it is a leaf as the pair is,
30
+ * and it sits beside `branchFromTemplate`, the writer it reads back.
31
+ *
32
+ * ## What it exports
33
+ *
34
+ * Each name is spelled, types apart from values, as the entries
35
+ * `src/index.ts` and `src/plan/index.ts` spell theirs.
36
+ *
37
+ * `sections.test.ts` holds the list to the three files: every name any
38
+ * of them exports is here once, as the same binding, and no name is here
39
+ * that none of them exports.
40
+ */
41
+ export type { ReleasePublishMode, ReleaseSettleMode, ReleaseStrategy, ReleaseTagMode, VersionCollisionMode, } from './config-readers.js';
42
+ export type { BoardRelationshipMode, ClaimsAhead, ClaimsStaleAfter, ClaudeSettingSource, ConfigExtra, ConfigVersion, DuplicatesLevel, InjectMode, LessonSwitch, Mapping, OutputMode, PrProvider, Reader, Reading, ReleaseEnabled, RouteTarget, SkillResolverName, StoreBackend, SyncStrategy, TierPin, TierSwitch, ValueAt, } from './config-sections.js';
43
+ export { branchGlob, stubOfBranch } from './branch-template.js';
44
+ export { BRANCH_STUB, branchFromTemplate, branchTemplate, DEFAULT_BRANCH_TEMPLATE, directory, fragmentsDirectory, isBranchTemplate, mapOf, RELEASE_PUBLISH_MODES, RELEASE_SETTLE_MODES, RELEASE_STRATEGIES, RELEASE_TAG_MODES, releaseFile, releasePublishMode, releaseSettleMode, releaseStrategy, releaseTagMode, routeTable, tierPins, trackerKind, VERSION_COLLISION_MODES, versionCollisionMode, } from './config-readers.js';
45
+ export { below, BOARD_PROJECT_TEMPLATE_DEFAULT, BOARD_RELATIONSHIP_MODES, BUSY_TIMEOUT_MAX_MS, BUSY_TIMEOUT_MIN_MS, busyTimeoutMs, claimDurationHours, CLAIMS_AHEAD, CLAIMS_STALE_DISABLED, claimsAhead, claimsStaleAfter, CLAUDE_SETTING_SOURCES, confidence, CONFIDENCE_MAX, CONFIDENCE_MIN, CONFIG_VERSIONS, dayCount, describeValue, DUPLICATE_LEVELS, duplicatesLevel, flag, githubLogin, INJECT_MODES, isBusyTimeoutMs, isGitHubLogin, isMapping, issueNumber, LESSON_SWITCHES, lessonSwitch, listOf, mapReading, messageOf, oneOf, OUTPUT_MODES, PR_PROVIDERS, projectNumber, projectUrl, recurrenceCount, refused, refusedWith, RELEASE_AUTO, releaseEnabled, routeTarget, SKILL_RESOLVERS, skillResolverName, STORE_BACKENDS, subsetOf, SYNC_STRATEGIES, text, TIER_SWITCHES, tierPin, tierSwitch, usdAmount, } from './config-sections.js';
@@ -0,0 +1,27 @@
1
+ import type { ConfigSection } from './section.js';
2
+ import type { StandardSchemaV1 } from '@open-tomato/define-config';
3
+ /** The vendor every schema built here names. */
4
+ export declare const SCHEMA_VENDOR = "rafa";
5
+ /**
6
+ * One pair of `createLoader`'s `schema` list: the key path of the
7
+ * subtree, outermost key first, and the schema that subtree must
8
+ * satisfy. The empty path names the whole value.
9
+ */
10
+ export type ConfigSchemaSection = readonly [path: readonly string[], schema: StandardSchemaV1];
11
+ /**
12
+ * A Standard Schema V1 schema whose `validate` runs `section`'s readers
13
+ * over the merged mapping and answers one issue per refusal at the
14
+ * refused key's path; see the module note.
15
+ *
16
+ * @param section - The section whose settings' readers judge the value.
17
+ * @returns A schema validating synchronously, vendor {@link SCHEMA_VENDOR}.
18
+ */
19
+ export declare function schemaOf(section: ConfigSection): StandardSchemaV1;
20
+ /**
21
+ * The `[path, schema]` list `createLoader`'s `schema` option takes: one
22
+ * pair per section, in the order given, each at the empty path.
23
+ *
24
+ * @param sections - The sections to validate the merged config with.
25
+ * @returns One frozen pair per section.
26
+ */
27
+ export declare function schemaSectionsOf(sections: readonly ConfigSection[]): readonly ConfigSchemaSection[];
@@ -0,0 +1,232 @@
1
+ /**
2
+ * Conventional type of a derived subject.
3
+ *
4
+ * Exactly the six {@link COMMIT_TYPE_RULES} can select, one of which
5
+ * is also {@link DEFAULT_COMMIT_TYPE}. `ci` and `perf` are legal in
6
+ * this repo's history and are absent here on purpose: no rule selects
7
+ * them, and a member the inference can never answer would be a column
8
+ * that always reads empty.
9
+ */
10
+ export type CommitType = 'chore' | 'docs' | 'feat' | 'fix' | 'refactor' | 'test';
11
+ /** What a task text is labelled when no rule matches it. */
12
+ export declare const DEFAULT_COMMIT_TYPE: CommitType;
13
+ /** One inference rule. The first whose pattern matches wins. */
14
+ export interface CommitTypeRule {
15
+ /** Type this rule selects. */
16
+ type: CommitType;
17
+ /** Matched against the normalised, still-capitalised task text. */
18
+ pattern: RegExp;
19
+ }
20
+ /**
21
+ * The inference table, in priority order.
22
+ *
23
+ * It is a LABEL and not a classification: a wrong type costs a
24
+ * slightly-off word at the front of a subject whose body carries the
25
+ * whole task text, so the rules are kept few and readable rather
26
+ * than exhaustive. Two orderings in it are load-bearing.
27
+ *
28
+ * `test` runs first because a test task is the one shape whose verb
29
+ * is indistinguishable from a feature's — both begin `Add` — and only
30
+ * the noun separates them.
31
+ *
32
+ * `docs` runs before every verb rule because a documentation task's
33
+ * verb is whatever the edit happens to be (`Remove the four commit
34
+ * instructions from PROMPT.md`, `Rewrite the root AGENTS.md`,
35
+ * `Split packages/service/AGENTS.md`), while the thing it names is
36
+ * reliably a markdown file. The known cost of that order is a real
37
+ * code task that merely mentions a `.md` path, which is labelled
38
+ * `docs`; the body still says what it did.
39
+ */
40
+ export declare const COMMIT_TYPE_RULES: readonly CommitTypeRule[];
41
+ /**
42
+ * Longest subject this module will produce, including the type
43
+ * prefix. Git's own convention, and the ceiling GitHub renders
44
+ * without eliding.
45
+ */
46
+ export declare const MAX_SUBJECT_LENGTH = 72;
47
+ /** Description used when the task text carries no words at all. */
48
+ export declare const FALLBACK_DESCRIPTION = "complete the scoped task";
49
+ /**
50
+ * Characters of a failed git invocation kept on the result.
51
+ *
52
+ * A rejected hook can print a finding per staged file, and the loop
53
+ * echoes this to a console a human is scrolling. Truncation is
54
+ * marked, so a caller can tell a short message from a cut one.
55
+ */
56
+ export declare const MAX_MESSAGE_CHARS = 4000;
57
+ /** Collapses every whitespace run, newlines included, to one space. */
58
+ export declare function normaliseTaskText(taskText: string): string;
59
+ /**
60
+ * Picks the conventional type for a task text.
61
+ *
62
+ * Falls back to {@link DEFAULT_COMMIT_TYPE}, which is what an
63
+ * unrecognised verb gets rather than an exception: the loop must
64
+ * still be able to commit a task whose wording nobody anticipated.
65
+ */
66
+ export declare function inferCommitType(taskText: string): CommitType;
67
+ /**
68
+ * The task text up to its first comma, colon or parenthesis outside a
69
+ * code span, trailing whitespace dropped. The whole text when nothing
70
+ * ends it, and the empty string when the text opens on an ending.
71
+ *
72
+ * A subject quotes the first clause rather than the first 72
73
+ * characters because a width cut stops wherever the width falls: the
74
+ * 2026-09-14 cutover run committed a subject ending `(under 60 lines)
75
+ * stating that the loop`, mid-sentence, where the clause before the
76
+ * parenthesis was the whole of what it needed to say.
77
+ *
78
+ * The code-span exception is what makes the rule usable on a plan,
79
+ * which names identifiers in backticks: the comma in `run(a, b)` is
80
+ * part of a name, never the end of a clause. A backtick run that
81
+ * nothing closes opens no span, as CommonMark reads it, so it is
82
+ * literal text and the endings after it still count.
83
+ */
84
+ export declare function firstClause(text: string): string;
85
+ /** How a subject is built. */
86
+ export interface SubjectOptions {
87
+ /** Conventional scope, rendered as `type(scope):`. Optional. */
88
+ scope?: string;
89
+ /** Cap including the prefix. Defaults to {@link MAX_SUBJECT_LENGTH}. */
90
+ maxLength?: number;
91
+ }
92
+ /** A derived subject and what deriving it decided. */
93
+ export interface DerivedSubject {
94
+ /** The whole subject line, prefix included. */
95
+ subject: string;
96
+ /** Type the rules selected. */
97
+ type: CommitType;
98
+ /**
99
+ * True when the description was cut to fit the cap. Ending at the
100
+ * first clause is not a cut: a clause that fits answers false
101
+ * however much task text follows it.
102
+ */
103
+ truncated: boolean;
104
+ }
105
+ /**
106
+ * Derives a conventional-commit subject from a task's text.
107
+ *
108
+ * The description is the text's {@link firstClause}, cut at a word
109
+ * boundary when that clause alone is longer than the cap leaves room
110
+ * for. The TYPE is still inferred from the whole text, since a clause
111
+ * can end before the path or the noun the rules read. Whatever the
112
+ * subject leaves out, the body {@link buildCommitMessage} writes
113
+ * carries.
114
+ *
115
+ * Deterministic over its input: the same task text answers the same
116
+ * subject on every machine and every run, which is what lets the
117
+ * loop's commits be predicted by a test instead of inspected by a
118
+ * human.
119
+ */
120
+ export declare function deriveCommitSubject(taskText: string, options?: SubjectOptions): DerivedSubject;
121
+ /** A subject with the body that carries the whole task line. */
122
+ export interface CommitMessage extends DerivedSubject {
123
+ /**
124
+ * The whole normalised task text, written whatever the subject kept
125
+ * of it. The empty string only for a task text with no words, which
126
+ * has no line to carry.
127
+ */
128
+ body: string;
129
+ }
130
+ /**
131
+ * Builds the message a task's commit is made with.
132
+ *
133
+ * The body is the whole task line on every commit. The subject holds
134
+ * one clause at most, so it seldom carries the sentence, and a body
135
+ * written only when the subject lost words would leave a reader of
136
+ * `git log` checking, commit by commit, which of the two holds it. The
137
+ * sentence is the only record of what the commit was asked to do, so
138
+ * it sits in the same place every time, even where that repeats a
139
+ * subject that already says all of it.
140
+ */
141
+ export declare function buildCommitMessage(taskText: string, options?: SubjectOptions): CommitMessage;
142
+ /** Argv that stages the whole worktree. */
143
+ export declare function stageAllArgs(): string[];
144
+ /**
145
+ * Argv that answers whether anything is staged: exit 0 for nothing,
146
+ * exit 1 for something. Exported so a caller reading the exit code
147
+ * can see which command produced it.
148
+ */
149
+ export declare function stagedChangesArgs(): string[];
150
+ /**
151
+ * Argv that makes the commit.
152
+ *
153
+ * `--cleanup=whitespace` is spelled out because strip DELETES every
154
+ * line beginning with `#`, and a task text is free to open on a shell
155
+ * comment or a markdown heading. It is NOT defending against git's
156
+ * default: for a `-m` message the default already behaves as
157
+ * whitespace, strip being the default only when the message is to be
158
+ * edited. What it defends against is a `commit.cleanup=strip`
159
+ * CONFIGURATION, which a machine's global git config is free to set
160
+ * (measured, git 2.50.1). Since {@link buildCommitMessage} collapses
161
+ * the task text to one line, the whole reachable difference is a task
162
+ * text that OPENS on a hash.
163
+ *
164
+ * Two `-m` arguments rather than one joined string: git inserts the
165
+ * blank line between subject and body itself, so the separator
166
+ * cannot drift.
167
+ */
168
+ export declare function commitArgs(subject: string, body?: string): string[];
169
+ /** Argv that reads the sha the commit just produced. */
170
+ export declare function headShaArgs(): string[];
171
+ /** One git invocation's result, as the runner reports it. */
172
+ export interface GitRunResult {
173
+ /** Exit code, or null when the process was killed or never ran. */
174
+ status: number | null;
175
+ stdout: string;
176
+ stderr: string;
177
+ }
178
+ /** Runs git with the given argv. The seam every test drives. */
179
+ export type GitRunner = (args: string[]) => GitRunResult;
180
+ /** Which invocation a failure came from. */
181
+ export type CommitStep = 'stage' | 'inspect' | 'commit';
182
+ /** What one attempt did. */
183
+ export type CommitOutcome = 'committed' | 'nothing-to-commit' | 'failed';
184
+ /** The whole result of one attempt. */
185
+ export interface CommitAttempt {
186
+ outcome: CommitOutcome;
187
+ /** Subject the commit was made with, derived either way. */
188
+ subject: string;
189
+ /** Sha of the new commit, or null when none was made. */
190
+ sha: string | null;
191
+ /** Invocation that failed, or null when none did. */
192
+ failedStep: CommitStep | null;
193
+ /** That invocation's exit code, or null. */
194
+ exitCode: number | null;
195
+ /** Its stderr and stdout, capped. Empty when nothing failed. */
196
+ message: string;
197
+ }
198
+ /** How an attempt is made. */
199
+ export interface CommitOptions {
200
+ /** The task's text, which the subject is derived from. */
201
+ taskText: string;
202
+ /** Directory git runs in. Defaults to the current one. */
203
+ cwd?: string;
204
+ /** Conventional scope for the subject. Optional. */
205
+ scope?: string;
206
+ /** Cap for the subject. Defaults to {@link MAX_SUBJECT_LENGTH}. */
207
+ maxLength?: number;
208
+ /** Runner override. Defaults to a real `git` spawn in `cwd`. */
209
+ runGit?: GitRunner;
210
+ }
211
+ /**
212
+ * The default runner: a real `git` in `cwd`.
213
+ *
214
+ * `spawnSync` and not `execFileSync`, because two of the three
215
+ * invocations use their exit code as an ANSWER rather than as an
216
+ * error — `git diff --cached --quiet` exits 1 to say a commit is
217
+ * warranted, and a thrown exception there would turn the ordinary
218
+ * case into the failure path.
219
+ */
220
+ export declare function spawnGit(cwd: string): GitRunner;
221
+ /**
222
+ * Stages the worktree and commits it under a subject derived from
223
+ * the task's text.
224
+ *
225
+ * The three invocations run in a fixed order and each one's failure
226
+ * stops the attempt, so a caller never sees a `committed` result
227
+ * whose commit did not happen. The fourth read — the sha — is the
228
+ * exception: it runs AFTER the commit succeeded, so a failure there
229
+ * leaves the outcome `committed` with a null sha rather than
230
+ * retracting a commit that is already in the history.
231
+ */
232
+ export declare function commitTaskWork(options: CommitOptions): CommitAttempt;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The seam every `gh` command goes through: the runner's type and what
3
+ * one command answers.
4
+ *
5
+ * Declared here, below the `github` tracker that spawns `gh`, so the
6
+ * adapter registry types its `gh` option without importing the tracker.
7
+ * `src/adapters/tracker/github.ts` imports both names from this file
8
+ * and re-exports them under the same names, so none of its importers
9
+ * changes.
10
+ */
11
+ /** What one `gh` command answered. */
12
+ export interface GhResult {
13
+ /** True when `gh` exited 0. */
14
+ readonly ok: boolean;
15
+ readonly stdout: string;
16
+ readonly stderr: string;
17
+ }
18
+ /**
19
+ * Runs `gh` with the arguments after its name. A command that fails,
20
+ * or could not be run, answers `ok` false rather than rejecting.
21
+ * `stdin`, when given, is the whole of what `gh` reads on its standard
22
+ * input; left out, `gh` reads a closed one.
23
+ */
24
+ export type GhRunner = (args: readonly string[], stdin?: string) => Promise<GhResult>;
@@ -0,0 +1,22 @@
1
+ /** What one git command answered. Never a throw; see the module note. */
2
+ export interface GitResult {
3
+ /** True when git exited 0. */
4
+ readonly ok: boolean;
5
+ /** Its standard output, empty when it wrote none. */
6
+ readonly stdout: string;
7
+ /** Its standard error, empty when it wrote none. */
8
+ readonly stderr: string;
9
+ }
10
+ /** Runs git with the arguments after its name, in the directory it was made for. */
11
+ export type GitRunner = (args: readonly string[]) => GitResult;
12
+ /**
13
+ * Makes the runner that spawns `git` in `cwd`, under `LC_ALL=C`, with
14
+ * its output read as UTF-8. It never throws; see the module note.
15
+ */
16
+ export declare function createGitRunner(cwd: string): GitRunner;
17
+ /**
18
+ * What git said, its standard error first, since that is where it
19
+ * writes its refusals and its progress. Empty when it said nothing at
20
+ * all, which a successful `git switch` does.
21
+ */
22
+ export declare function gitSaid(result: GitResult): string;
@@ -0,0 +1,85 @@
1
+ /**
2
+ * The barrel over git: every name `git.ts`, `commit.ts` and
3
+ * `gh-runner.ts` export but one, and nothing else.
4
+ *
5
+ * A file outside `packages/rafa/src/core/` imports this file and never the two behind
6
+ * it (`scripts/survey/core-barrels.ts` measures that, and
7
+ * `src/tests/core-barrels.sweep.test.ts` holds it against the tree). A
8
+ * file inside `packages/rafa/src/core/` imports the two directly and never this file.
9
+ * None does today.
10
+ *
11
+ * ## What sits behind it
12
+ *
13
+ * - `git.ts`: the runner that spawns `git` in a directory and answers
14
+ * what git said instead of throwing, with the reader of that answer;
15
+ * - `commit.ts`: staging and committing one task's work on the loop's
16
+ * behalf, the subject derived from the task text, and the argv of
17
+ * each step;
18
+ * - `gh-runner.ts`: the type of the runner every `gh` command goes
19
+ * through and what one command answers, types alone, imported by
20
+ * nothing.
21
+ *
22
+ * ## The one name the two files share
23
+ *
24
+ * Both files export a type named `GitRunner`, and they are two types.
25
+ * `git.ts` declares `(args: readonly string[]) => GitResult`, the seam
26
+ * the callers of this barrel stub. `commit.ts` declares
27
+ * `(args: string[]) => GitRunResult`, the runner `CommitOptions.runGit`
28
+ * takes, which carries an exit status where the first carries `ok`.
29
+ *
30
+ * One barrel exports one binding under a name, so `GitRunner` here is
31
+ * the one `git.ts` declares, and the one of `commit.ts` is not exported
32
+ * from this file. The move changed paths and no logic, so neither type
33
+ * was renamed, and the barrel coins no second name for the one it
34
+ * leaves out.
35
+ *
36
+ * Measured when the two moved: 138 files under `src/` imported
37
+ * `git.ts`, and 107 of them took its `GitRunner`. Eleven imported
38
+ * `commit.ts`, and one of those took its `GitRunner`:
39
+ * `commit.test.ts`, which moved with it and imports it directly. A
40
+ * caller outside `packages/rafa/src/core/` that stubs the commit runner types it
41
+ * through `CommitOptions['runGit']`, and `GitRunResult` is exported for
42
+ * what it answers.
43
+ *
44
+ * ## Why one barrel can hold both
45
+ *
46
+ * A barrel that groups a file with a file outside `packages/rafa/src/core/` that
47
+ * imports the barrel back by value is a runtime cycle. `commit.ts`
48
+ * imports `node:child_process` and no file. `git.ts` imports one file by
49
+ * value: `packages/rafa/src/core/config/config-sections.ts`, for `messageOf`. That
50
+ * file imports one file outside `packages/rafa/src/core/` by value,
51
+ * `packages/rafa/src/schema/tiers.ts`, and it does not reach this barrel.
52
+ *
53
+ * `src/pr/index.ts`, the `pr` subject's barrel, re-exports the four
54
+ * names of `git.ts` from this file, as it re-exported them from
55
+ * `git.ts` before the move. `config-sections.ts` imports
56
+ * `src/pr/types.ts` directly and not that barrel, which is why the edge
57
+ * closes nothing.
58
+ *
59
+ * Measured when the two moved: the value imports of the non-test files
60
+ * under `src/` and `packages/` held six cycles before the move and the
61
+ * same six after it, none through a file of this folder. The control,
62
+ * the same tree with `src/pr/types.ts` taking one value (`gitSaid`) from
63
+ * this barrel, held a seventh: that file, `config-sections.ts`, `git.ts`
64
+ * and this one. No load order of the control was run.
65
+ *
66
+ * `docs/survey/cluster-map.json` places `git.ts` and `commit.ts` in two
67
+ * clusters, and this file, which it does not name, lands by its folder
68
+ * in the cluster of `git.ts`. `src/tests/import-cycle.sweep.test.ts`
69
+ * reads cycles and this file is in none.
70
+ *
71
+ * ## What it exports
72
+ *
73
+ * Each name is spelled, types apart from values, as the other core
74
+ * barrels spell theirs. No name here is part of the published surface:
75
+ * `src/index.ts` re-exports nothing from this file.
76
+ *
77
+ * `index.test.ts` holds the list to the two files: every name either
78
+ * exports is here once, as the same binding, `GitRunner` as the type
79
+ * `git.ts` declares, and no other name is here.
80
+ */
81
+ export type { GhResult, GhRunner } from './gh-runner.js';
82
+ export type { GitResult, GitRunner } from './git.js';
83
+ export type { CommitAttempt, CommitMessage, CommitOptions, CommitOutcome, CommitStep, CommitType, CommitTypeRule, DerivedSubject, GitRunResult, SubjectOptions, } from './commit.js';
84
+ export { createGitRunner, gitSaid } from './git.js';
85
+ export { buildCommitMessage, COMMIT_TYPE_RULES, commitArgs, commitTaskWork, DEFAULT_COMMIT_TYPE, deriveCommitSubject, FALLBACK_DESCRIPTION, firstClause, headShaArgs, inferCommitType, MAX_MESSAGE_CHARS, MAX_SUBJECT_LENGTH, normaliseTaskText, spawnGit, stageAllArgs, stagedChangesArgs, } from './commit.js';