@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.
- package/README.md +255 -23
- package/dist/PROMPT.md +18 -1
- package/dist/adapters/logger/settings.d.ts +132 -0
- package/dist/bugs/closest.d.ts +19 -0
- package/dist/bugs/fenced.d.ts +8 -0
- package/dist/bugs/places.d.ts +20 -0
- package/dist/bugs/record.d.ts +145 -0
- package/dist/bugs/title.d.ts +83 -0
- package/dist/bundled/agents/doc-updater.md +17 -3
- package/dist/bundled/agents/loop-implementer.md +14 -2
- package/dist/bundled/operators/skills/rafa-stretch-pit-stop/SKILL.md +10 -3
- package/dist/bundled/operators/skills/rafa-stretch-sweep/SKILL.md +5 -0
- package/dist/bundled/skills/dev-planner/SKILL.md +101 -18
- package/dist/cli.js +74726 -62960
- package/dist/config/entry.d.ts +119 -0
- package/dist/config/index.d.ts +36 -0
- package/dist/config/index.js +51 -0
- package/dist/config/shape.d.ts +232 -0
- package/dist/config-registry.d.ts +127 -0
- package/dist/config-schema-board-project.d.ts +157 -0
- package/dist/config-schema-bugs.d.ts +71 -0
- package/dist/config-schema-errors.d.ts +54 -0
- package/dist/config-schema-features.d.ts +64 -0
- package/dist/config-schema-hub.d.ts +150 -0
- package/dist/config-schema-issues.d.ts +95 -0
- package/dist/config-schema-logger.d.ts +91 -0
- package/dist/config-schema-loop-continue.d.ts +122 -0
- package/dist/config-schema-loop-retries.d.ts +94 -0
- package/dist/config-schema-release.d.ts +307 -0
- package/dist/config-schema-tests.d.ts +170 -0
- package/dist/config-schema-triage.d.ts +142 -0
- package/dist/config-schema-wrap-up.d.ts +96 -0
- package/dist/core/command/command.d.ts +228 -0
- package/dist/core/command/confirm.d.ts +67 -0
- package/dist/core/command/index.d.ts +112 -0
- package/dist/core/command/lazy.d.ts +54 -0
- package/dist/core/command/registry-types.d.ts +96 -0
- package/dist/core/command/running.d.ts +96 -0
- package/dist/core/command/spends.d.ts +39 -0
- package/dist/core/command/types.d.ts +92 -0
- package/dist/core/command/version.d.ts +4 -0
- package/dist/core/config/branch-template.d.ts +20 -0
- package/dist/core/config/config-items.d.ts +86 -0
- package/dist/core/config/config-load.d.ts +47 -0
- package/dist/core/config/config-origins.d.ts +57 -0
- package/dist/core/config/config-readers.d.ts +167 -0
- package/dist/core/config/config-schema.d.ts +207 -0
- package/dist/core/config/config-sections.d.ts +493 -0
- package/dist/core/config/config.d.ts +320 -0
- package/dist/core/config/core-section.d.ts +39 -0
- package/dist/core/config/dangerous.d.ts +58 -0
- package/dist/core/config/default-routing.d.ts +16 -0
- package/dist/core/config/index.d.ts +141 -0
- package/dist/core/config/scope.d.ts +42 -0
- package/dist/core/config/section.d.ts +206 -0
- package/dist/core/config/sections.d.ts +45 -0
- package/dist/core/config/standard-schema.d.ts +27 -0
- package/dist/core/git/commit.d.ts +232 -0
- package/dist/core/git/gh-runner.d.ts +24 -0
- package/dist/core/git/git.d.ts +22 -0
- package/dist/core/git/index.d.ts +85 -0
- package/dist/core/loop/claude.d.ts +388 -0
- package/dist/core/loop/hop-record.d.ts +52 -0
- package/dist/core/loop/index.d.ts +179 -0
- package/dist/core/loop/session-env.d.ts +20 -0
- package/dist/core/loop/session-record-parse.d.ts +63 -0
- package/dist/core/loop/sessions.d.ts +408 -0
- package/dist/core/loop/suite-failure.d.ts +25 -0
- package/dist/core/output/active.d.ts +100 -0
- package/dist/core/output/stream.d.ts +20 -0
- package/dist/core/output/text.d.ts +55 -0
- package/dist/core/plan/block-reader.d.ts +46 -0
- package/dist/core/plan/blocks.d.ts +139 -0
- package/dist/core/plan/declaration.d.ts +366 -0
- package/dist/core/plan/plan-stamp.d.ts +75 -0
- package/dist/core/runtime/identity.d.ts +21 -0
- package/dist/core/runtime/index.d.ts +46 -0
- package/dist/effort/store/bring-forward.d.ts +131 -0
- package/dist/effort/store/check-rows.d.ts +31 -0
- package/dist/effort/store/commit-stats.d.ts +42 -0
- package/dist/effort/store/copy.d.ts +35 -0
- package/dist/effort/store/development-build.d.ts +105 -0
- package/dist/effort/store/effort-levels.d.ts +13 -0
- package/dist/effort/store/findings.d.ts +214 -0
- package/dist/effort/store/fix-schema.d.ts +184 -0
- package/dist/effort/store/index.js +10 -7
- package/dist/effort/store/location.d.ts +44 -0
- package/dist/effort/store/merge-commit-gaps.d.ts +68 -0
- package/dist/effort/store/merge-conflicts.d.ts +91 -0
- package/dist/effort/store/merge-rules.d.ts +82 -0
- package/dist/effort/store/merge-store.d.ts +211 -0
- package/dist/effort/store/merge-union.d.ts +92 -0
- package/dist/effort/store/migrate.d.ts +146 -0
- package/dist/effort/store/migrations.d.ts +92 -0
- package/dist/effort/store/ndjson-files.d.ts +114 -0
- package/dist/effort/store/origins.d.ts +116 -0
- package/dist/effort/store/plan-stubs.d.ts +79 -0
- package/dist/effort/store/rebuild-aside.d.ts +172 -0
- package/dist/effort/store/schema-plan.d.ts +102 -0
- package/dist/effort/store/session-row-types.d.ts +64 -0
- package/dist/effort/store/settings.d.ts +13 -0
- package/dist/effort/store/sqlite.d.ts +340 -0
- package/dist/effort/store/store-generation.d.ts +17 -0
- package/dist/effort/store/store-identity.d.ts +220 -0
- package/dist/effort/store/store-meta.d.ts +305 -0
- package/dist/effort/store/store-replaced.d.ts +72 -0
- package/dist/effort/store/types.d.ts +223 -0
- package/dist/errors/codes.d.ts +56 -0
- package/dist/errors/rafa-codes.d.ts +36 -0
- package/dist/index-2a7nb3an.js +125 -0
- package/dist/{index-r28fzsvc.js → index-39kbcw68.js} +350 -165
- package/dist/{index-nv34ptht.js → index-77ajfffn.js} +14 -9
- package/dist/index-cy98y87p.js +2597 -0
- package/dist/index-gqz4jn6j.js +13447 -0
- package/dist/index-gvek4r8m.js +710 -0
- package/dist/index-j4k2vdz3.js +1125 -0
- package/dist/index-jh1r4kcn.js +1067 -0
- package/dist/{index-mgh2s9bj.js → index-ykggr043.js} +58 -455
- package/dist/index-z1w83f81.js +4 -0
- package/dist/index.js +14715 -21516
- package/dist/learning/index.js +5 -6
- package/dist/plan/index.js +12 -11
- package/dist/plan-prompt.md +3 -1
- package/dist/ports/index.d.ts +732 -0
- package/dist/ports/learning.d.ts +101 -0
- package/dist/ports/log-level.d.ts +13 -0
- package/dist/ports/spec-review.d.ts +66 -0
- package/dist/pr/checks.d.ts +133 -0
- package/dist/pr/types.d.ts +422 -0
- package/dist/ready-4f8edezt.js +2016 -0
- package/dist/release-templates/release-bot-fragment.yml +153 -0
- package/dist/release-templates/release-publish.yml +110 -0
- package/dist/release-templates/release-settle.yml +122 -0
- package/dist/release-templates/release-tag.yml +102 -0
- package/dist/report/parse.d.ts +415 -0
- package/dist/schema/project-id.d.ts +79 -0
- package/dist/schema/tiers.d.ts +107 -0
- package/package.json +41 -3
- package/dist/index-hf2k497d.js +0 -16
- package/dist/index-nsr78ct2.js +0 -8219
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The line prompter: the one prompt that reads whole lines, not keys as
|
|
3
|
+
* `src/cli/prompt/`'s do, so it needs no raw mode and works on a pipe as
|
|
4
|
+
* well as on a terminal. Every yes-or-no question rafa asks, and the root
|
|
5
|
+
* `rafa init` reads, goes through a {@link Prompter}; the commands take
|
|
6
|
+
* one from {@link createLinePrompter} over `process.stdin` and
|
|
7
|
+
* `process.stderr`, and tests pass a scripted one.
|
|
8
|
+
*
|
|
9
|
+
* ## The prompter
|
|
10
|
+
*
|
|
11
|
+
* {@link createLinePrompter} reads lines from a stream with `readline`'s
|
|
12
|
+
* `line` and `close` events, and writes each question and each thing it
|
|
13
|
+
* says to another stream. It does not use `readline/promises`: measured
|
|
14
|
+
* on bun 1.3.14, a `question` pending when its input ends never settles,
|
|
15
|
+
* where the `close` event fires. The final line of an input that ends
|
|
16
|
+
* without a line break is still delivered as a line, measured the same
|
|
17
|
+
* way. readline is given no output and `terminal: false`, so on a
|
|
18
|
+
* terminal the terminal's own line discipline echoes and edits what is
|
|
19
|
+
* typed.
|
|
20
|
+
*
|
|
21
|
+
* Two line prompters over one input both receive every line, so a
|
|
22
|
+
* command handing a question to another closes its own first.
|
|
23
|
+
*
|
|
24
|
+
* ## The lazy prompter
|
|
25
|
+
*
|
|
26
|
+
* {@link lazyPrompter} wraps the opening of a prompter so a run that
|
|
27
|
+
* never asks opens nothing: the prompter is opened at the first
|
|
28
|
+
* question, kept for the next, and closed by `close`, after which the
|
|
29
|
+
* next question opens a fresh one. Its `ask` answers whether the line
|
|
30
|
+
* typed means yes: `y` or `yes`, trimmed and in any case, the reading
|
|
31
|
+
* every `[y/N]` question in rafa makes. Anything else declines, the empty
|
|
32
|
+
* answer and the null of an input that ended included. `issue ready`,
|
|
33
|
+
* `next`, `cleanup` and `plan create`'s three offers ask through it.
|
|
34
|
+
*/
|
|
35
|
+
import type { Readable } from 'node:stream';
|
|
36
|
+
/** Asks an operator, and tells them what went wrong. */
|
|
37
|
+
export interface Prompter {
|
|
38
|
+
/** Writes `text` and a line break. */
|
|
39
|
+
readonly say: (text: string) => void;
|
|
40
|
+
/** Writes `question` and answers the next line typed, or null once the input has ended. */
|
|
41
|
+
readonly ask: (question: string) => Promise<string | null>;
|
|
42
|
+
/** Stops reading the input. */
|
|
43
|
+
readonly close: () => void;
|
|
44
|
+
}
|
|
45
|
+
/** A prompter opened at its first question, see the module note. */
|
|
46
|
+
export interface LazyPrompter {
|
|
47
|
+
/** Opens the prompter if it is not open, asks `question` and answers whether the line typed means yes. */
|
|
48
|
+
readonly ask: (question: string) => Promise<boolean>;
|
|
49
|
+
/** Closes the prompter if one is open; the next question opens another. */
|
|
50
|
+
readonly close: () => void;
|
|
51
|
+
}
|
|
52
|
+
/** A stream the prompter writes to: `process.stderr`, or a test's own. */
|
|
53
|
+
export interface PromptOutput {
|
|
54
|
+
readonly write: (chunk: string) => unknown;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* A {@link Prompter} reading lines from `input` and writing to `output`;
|
|
58
|
+
* see the module note. A line typed before it is asked for is kept for
|
|
59
|
+
* the next question.
|
|
60
|
+
*/
|
|
61
|
+
export declare function createLinePrompter(input: Readable, output: PromptOutput): Prompter;
|
|
62
|
+
/**
|
|
63
|
+
* A {@link LazyPrompter} over `open`, which is called at the first
|
|
64
|
+
* question and again at the first one after each `close`; see the
|
|
65
|
+
* module note.
|
|
66
|
+
*/
|
|
67
|
+
export declare function lazyPrompter(open: () => Prompter): LazyPrompter;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The barrel over the command contract: every name `command.ts`,
|
|
3
|
+
* `confirm.ts`, `lazy.ts`, `registry-types.ts`, `running.ts`,
|
|
4
|
+
* `spends.ts`, `types.ts` and `version.ts` export, and nothing else.
|
|
5
|
+
*
|
|
6
|
+
* A file outside `packages/rafa/src/core/` imports this file and never the eight
|
|
7
|
+
* behind 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 eight directly and never this
|
|
10
|
+
* file.
|
|
11
|
+
*
|
|
12
|
+
* ## What sits behind it
|
|
13
|
+
*
|
|
14
|
+
* - `command.ts`: `RafaCommand`, the `RafaContext` it runs with,
|
|
15
|
+
* `CommandExit`, the routing words and the shape check;
|
|
16
|
+
* - `confirm.ts`: the `Prompter` every yes-or-no question goes
|
|
17
|
+
* through, the line prompter that reads one from a stream, and the
|
|
18
|
+
* lazy prompter that opens one only to ask;
|
|
19
|
+
* - `lazy.ts`: `CommandDeclaration`, a command less its `run`, and
|
|
20
|
+
* `lazyCommand`, the command over a declaration whose `run` imports
|
|
21
|
+
* the command's module and delegates to its default export;
|
|
22
|
+
* - `registry-types.ts`: the contract of the dispatcher's registry,
|
|
23
|
+
* `CommandRegistry` and the five shapes it names, and
|
|
24
|
+
* `CommandFeature`, what one feature contributes to it, whose
|
|
25
|
+
* builder stays in `src/cli/registry.ts`;
|
|
26
|
+
* - `running.ts`: the command this process is running with its parsed
|
|
27
|
+
* flags, recorded by the dispatcher and read by the spend guard;
|
|
28
|
+
* - `spends.ts`: a command's `spends` declaration, `CommandSpend`, its
|
|
29
|
+
* shape check and the mark help ends a spender's roster line with;
|
|
30
|
+
* - `types.ts`: the contracts copied from open-tomato's `cli-core`,
|
|
31
|
+
* `CliContext`, `CliCommand`, `ArgSpec` and `FlagSpec`, which
|
|
32
|
+
* `RafaCommand` extends;
|
|
33
|
+
* - `version.ts`: the version the running build answers with, and the
|
|
34
|
+
* line that spells it.
|
|
35
|
+
*
|
|
36
|
+
* The eight hold no name in common, so each name is exported once and
|
|
37
|
+
* from the file that declares it.
|
|
38
|
+
*
|
|
39
|
+
* ## Why one barrel can hold all eight
|
|
40
|
+
*
|
|
41
|
+
* A barrel that groups a file with a file outside `packages/rafa/src/core/` that
|
|
42
|
+
* imports the barrel back by value is a runtime cycle. None of the eight
|
|
43
|
+
* imports a file outside `packages/rafa/src/core/` by value. `command.ts` takes
|
|
44
|
+
* `spendsProblem` from `spends.ts` beside it, and both take
|
|
45
|
+
* `describeValue` from `packages/rafa/src/core/config/config-sections.ts`.
|
|
46
|
+
* `lazy.ts` takes the shape check, `CommandExit` and `commandSpelling`
|
|
47
|
+
* from `command.ts`, and `messageOf` from the same config file; the
|
|
48
|
+
* module a lazy command loads is the caller's `load()`, imported when
|
|
49
|
+
* the command runs, never by `lazy.ts` itself.
|
|
50
|
+
* `confirm.ts` and `running.ts` import `node:` modules alone by value,
|
|
51
|
+
* `running.ts` naming `command.ts` and `types.ts` with `import type`.
|
|
52
|
+
* `version.ts` imports the root `package.json`, and `types.ts` nothing
|
|
53
|
+
* by value: it names `packages/rafa/src/core/config/config-sections.ts` and the
|
|
54
|
+
* `Output` port with `import type`. `registry-types.ts` imports nothing
|
|
55
|
+
* by value either: it names `command.ts` with `import type`, and this
|
|
56
|
+
* file exports its names with `export type`, so loading the barrel
|
|
57
|
+
* never loads it.
|
|
58
|
+
*
|
|
59
|
+
* `command.ts` also names `src/project/scope.ts` with `import type`,
|
|
60
|
+
* which is erased before anything loads; it named `src/cli/registry.ts`
|
|
61
|
+
* the same way until the registry's contract moved into
|
|
62
|
+
* `registry-types.ts`. `src/cli/registry.ts` imports this barrel by
|
|
63
|
+
* value, for the shape check and the routing words, so that edge is the
|
|
64
|
+
* one a value import in `command.ts` would turn into a cycle.
|
|
65
|
+
*
|
|
66
|
+
* Measured when the three moved: the value imports of the non-test files
|
|
67
|
+
* under `src/` and `packages/` held six cycles before the move and the
|
|
68
|
+
* same six after it, none through a file of this folder. The control,
|
|
69
|
+
* the same tree with `command.ts` taking one value (`HELP_WORD`) from
|
|
70
|
+
* `src/cli/registry.ts`, held a seventh: `src/cli/registry.ts`,
|
|
71
|
+
* `command.ts` and this file.
|
|
72
|
+
*
|
|
73
|
+
* Measured again when `types.ts` moved in, over every strongly connected
|
|
74
|
+
* set of the same value imports: five cycles at the base and five after
|
|
75
|
+
* the move, none through a file of this folder or of `src/cli/core/`.
|
|
76
|
+
* The same `HELP_WORD` control held a sixth, `src/cli/registry.ts`,
|
|
77
|
+
* `command.ts` and this file.
|
|
78
|
+
*
|
|
79
|
+
* Measured again when `spends.ts` moved in, the same way: five cycles at
|
|
80
|
+
* the base and five after the move, none through a file of this folder
|
|
81
|
+
* or of `src/cli/`. The same `HELP_WORD` control held a sixth,
|
|
82
|
+
* `src/cli/registry.ts`, `command.ts` and this file.
|
|
83
|
+
*
|
|
84
|
+
* Measured again when the registry's contract moved into
|
|
85
|
+
* `registry-types.ts`, the same way: five cycles at the base and five
|
|
86
|
+
* after the move, none through a file of this folder or of `src/cli/`.
|
|
87
|
+
* The same `HELP_WORD` control held a sixth, `src/cli/registry.ts`,
|
|
88
|
+
* `command.ts` and this file.
|
|
89
|
+
*
|
|
90
|
+
* ## What it exports
|
|
91
|
+
*
|
|
92
|
+
* Each name is spelled, types apart from values, as the config barrels
|
|
93
|
+
* spell theirs. No name here is part of the published surface:
|
|
94
|
+
* `src/index.ts` re-exports nothing from this file.
|
|
95
|
+
*
|
|
96
|
+
* `index.test.ts` holds the list to the eight files: every name any of
|
|
97
|
+
* them exports is here once, as the same binding, and no other name is
|
|
98
|
+
* here.
|
|
99
|
+
*/
|
|
100
|
+
export type { CommandDeprecation, CommandExample, CommandOutput, FlagDeprecation, RafaCommand, RafaContext, RafaFlagSpec, } from './command.js';
|
|
101
|
+
export type { LazyPrompter, PromptOutput, Prompter } from './confirm.js';
|
|
102
|
+
export type { CommandDeclaration } from './lazy.js';
|
|
103
|
+
export type { CommandAlias, CommandFeature, CommandRegistry, CommandRegistryInput, ModuleMount, RosterOptions, SubjectSpec, } from './registry-types.js';
|
|
104
|
+
export type { RunningCommand } from './running.js';
|
|
105
|
+
export type { CommandSpend, SpendsWhen } from './spends.js';
|
|
106
|
+
export type { ArgSpec, CliCommand, CliContext, FlagSpec, } from './types.js';
|
|
107
|
+
export { COMMAND_OUTPUTS, CommandExit, commandProblem, commandSpelling, isRoutingWord, isTopLevel, } from './command.js';
|
|
108
|
+
export { createLinePrompter, lazyPrompter } from './confirm.js';
|
|
109
|
+
export { lazyCommand } from './lazy.js';
|
|
110
|
+
export { restoreRunningCommand, runAsRunningCommand, runningCommand, setRunningCommand, } from './running.js';
|
|
111
|
+
export { SPENDS_GLYPH, SPENDS_WHEN, spendsCondition, spendsMark, spendsProblem, } from './spends.js';
|
|
112
|
+
export { RAFA_VERSION, versionLine } from './version.js';
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A command whose module is imported when it runs, not when the roster
|
|
3
|
+
* is built: {@link lazyCommand} over a {@link CommandDeclaration}.
|
|
4
|
+
*
|
|
5
|
+
* ## What is declared and what is loaded
|
|
6
|
+
*
|
|
7
|
+
* A declaration is a `RafaCommand` less its `run`: every field routing,
|
|
8
|
+
* help, `describe` and the spend guard read, so a roster of lazy
|
|
9
|
+
* commands is built, routed and rendered without importing one command
|
|
10
|
+
* module. The lazy command is the declaration spread under a `run` of
|
|
11
|
+
* its own, so it passes `commandProblem` (`command.ts` beside this
|
|
12
|
+
* file) as the declaration's fields stand.
|
|
13
|
+
*
|
|
14
|
+
* Its `run` awaits `load()`, typically `() => import('./x.js')`, and
|
|
15
|
+
* holds the module's default export to a command: one `commandProblem`
|
|
16
|
+
* accepts, whose subject and action are the declaration's. It then hands
|
|
17
|
+
* the context to that command's `run` and settles as that `run`
|
|
18
|
+
* settles, a `CommandExit` it throws included. The loaded command's
|
|
19
|
+
* other fields are not compared with the declaration's: the dispatcher
|
|
20
|
+
* routed, parsed and guarded by the declaration's before `run` was
|
|
21
|
+
* called.
|
|
22
|
+
*
|
|
23
|
+
* ## Refusing
|
|
24
|
+
*
|
|
25
|
+
* A load that rejects, a default export `commandProblem` refuses, and a
|
|
26
|
+
* default export spelled as another command each refuse with
|
|
27
|
+
* `CommandExit(1, message)`, the message reading
|
|
28
|
+
* `feature "<feature>": command "<spelling>" failed to load: <reason>`.
|
|
29
|
+
* The spelling is `commandSpelling`'s, so a top-level command reads as
|
|
30
|
+
* its one word, as every other refusal naming a command spells it. The
|
|
31
|
+
* reason is the rejection's message, the shape check's sentence, or the
|
|
32
|
+
* spelling the export has against the one declared.
|
|
33
|
+
*
|
|
34
|
+
* Nothing is cached here: a second run calls `load()` again, and the
|
|
35
|
+
* module loader's own cache answers it.
|
|
36
|
+
*/
|
|
37
|
+
import type { RafaCommand } from './command.js';
|
|
38
|
+
/** A command less its `run`: what a feature declares for a command it loads when run. */
|
|
39
|
+
export type CommandDeclaration = Omit<RafaCommand, 'run'>;
|
|
40
|
+
/** What a command module's import resolves to: the command is its default export. */
|
|
41
|
+
type CommandModule = {
|
|
42
|
+
readonly default?: unknown;
|
|
43
|
+
} | null | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* A command spreading `declaration` under a `run` that loads the
|
|
46
|
+
* command and delegates to it. See the module note.
|
|
47
|
+
*
|
|
48
|
+
* @param declaration - Every field of the command but its `run`.
|
|
49
|
+
* @param load - Imports the command's module, whose default export is the command.
|
|
50
|
+
* @param feature - The name of the feature the command belongs to, which a refusal names.
|
|
51
|
+
* @returns The lazy command.
|
|
52
|
+
*/
|
|
53
|
+
export declare function lazyCommand(declaration: CommandDeclaration, load: () => Promise<CommandModule>, feature: string): RafaCommand;
|
|
54
|
+
export {};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The registry's contract: the {@link CommandRegistry} the dispatcher
|
|
3
|
+
* routes through, what it is built from, the subjects, aliases and
|
|
4
|
+
* mounts it answers, and the {@link CommandFeature} one feature hands
|
|
5
|
+
* the registry its subjects and commands in.
|
|
6
|
+
*
|
|
7
|
+
* The registry itself, `createCommandRegistry` and the refusals it
|
|
8
|
+
* throws, stays the CLI's, in `src/cli/registry.ts`, which imports
|
|
9
|
+
* these names from here and re-exports them under the same names. Core
|
|
10
|
+
* holds the contract alone, so `RafaContext` can name the registry a
|
|
11
|
+
* command runs with without importing a file above core.
|
|
12
|
+
*
|
|
13
|
+
* Every name here is a type: the file imports `RafaCommand` from
|
|
14
|
+
* `command.ts` beside it with `import type`, and nothing by value.
|
|
15
|
+
*/
|
|
16
|
+
import type { RafaCommand } from './command.js';
|
|
17
|
+
/** A subject: the first routing word, and what its roster line says. */
|
|
18
|
+
export interface SubjectSpec {
|
|
19
|
+
/** The routing word, singular: `issue`. */
|
|
20
|
+
readonly name: string;
|
|
21
|
+
/** One line for the root roster. */
|
|
22
|
+
readonly summary: string;
|
|
23
|
+
}
|
|
24
|
+
/** The commands one module's entry exports, mounted under `module/<name>`. */
|
|
25
|
+
export interface ModuleMount {
|
|
26
|
+
/** The word typed after an `exec` action: `linear` in `rafa module exec linear next`. */
|
|
27
|
+
readonly name: string;
|
|
28
|
+
/** The file the commands were imported from. */
|
|
29
|
+
readonly entry: string;
|
|
30
|
+
/** The commands, each routed by its action. */
|
|
31
|
+
readonly commands: readonly RafaCommand[];
|
|
32
|
+
}
|
|
33
|
+
/** One alias: the words it is typed as, the command it routes to, and whether it is kept for good. */
|
|
34
|
+
export interface CommandAlias {
|
|
35
|
+
readonly words: readonly string[];
|
|
36
|
+
readonly command: RafaCommand;
|
|
37
|
+
/** True for one of the command's `lastingAliases`, which prints no deprecation line. */
|
|
38
|
+
readonly lasting: boolean;
|
|
39
|
+
}
|
|
40
|
+
/** Whether a roster keeps hidden commands. */
|
|
41
|
+
export interface RosterOptions {
|
|
42
|
+
/** Keeps the commands declaring `hidden`. Off by default. */
|
|
43
|
+
readonly includeHidden?: boolean;
|
|
44
|
+
}
|
|
45
|
+
/** What a registry is built from. */
|
|
46
|
+
export interface CommandRegistryInput {
|
|
47
|
+
/** The subjects, in roster order. */
|
|
48
|
+
readonly subjects: readonly SubjectSpec[];
|
|
49
|
+
/** The core commands, in roster order. */
|
|
50
|
+
readonly commands: readonly RafaCommand[];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* What one feature contributes to a registry: its name, the subjects it
|
|
54
|
+
* declares and the commands under them, each list in roster order. The
|
|
55
|
+
* same two lists as a {@link CommandRegistryInput}, under the name that
|
|
56
|
+
* says which feature they came from.
|
|
57
|
+
*/
|
|
58
|
+
export interface CommandFeature {
|
|
59
|
+
/** The feature's name, which a load failure of one of its commands names. */
|
|
60
|
+
readonly name: string;
|
|
61
|
+
/** The subjects the feature declares, in roster order. */
|
|
62
|
+
readonly subjects: readonly SubjectSpec[];
|
|
63
|
+
/** The feature's commands, in roster order. */
|
|
64
|
+
readonly commands: readonly RafaCommand[];
|
|
65
|
+
}
|
|
66
|
+
/** The subjects, commands, aliases and mounts the dispatcher routes through. Never changes once made. */
|
|
67
|
+
export interface CommandRegistry {
|
|
68
|
+
/** The subjects, in the order declared. */
|
|
69
|
+
readonly subjects: () => readonly SubjectSpec[];
|
|
70
|
+
/** The subject a word names, as its name or its plural, or undefined. */
|
|
71
|
+
readonly subjectOf: (word: string) => SubjectSpec | undefined;
|
|
72
|
+
/** The core commands in the order declared, top-level ones included. */
|
|
73
|
+
readonly commands: (options?: RosterOptions) => readonly RafaCommand[];
|
|
74
|
+
/**
|
|
75
|
+
* The commands under a subject's name, or under a mount's key
|
|
76
|
+
* (`module/<name>`), in the order declared. Empty for a name holding
|
|
77
|
+
* none, a top-level command's included.
|
|
78
|
+
*/
|
|
79
|
+
readonly actionsOf: (subject: string, options?: RosterOptions) => readonly RafaCommand[];
|
|
80
|
+
/** The command under a subject's name or a mount's key, and an action, or undefined. */
|
|
81
|
+
readonly find: (subject: string, action: string) => RafaCommand | undefined;
|
|
82
|
+
/** The top-level command a word names, or undefined. */
|
|
83
|
+
readonly topLevel: (word: string) => RafaCommand | undefined;
|
|
84
|
+
/** Every alias, longest first, in the order declared among equals. */
|
|
85
|
+
readonly aliases: () => readonly CommandAlias[];
|
|
86
|
+
/** The mounts, in the order mounted. */
|
|
87
|
+
readonly mounts: () => readonly ModuleMount[];
|
|
88
|
+
/** The mount a module name names, or undefined. */
|
|
89
|
+
readonly mountOf: (name: string) => ModuleMount | undefined;
|
|
90
|
+
/**
|
|
91
|
+
* A new registry holding this one's mounts followed by `mount`, leaving
|
|
92
|
+
* this one unchanged. Throws, answering no registry, on a mount the
|
|
93
|
+
* module note refuses.
|
|
94
|
+
*/
|
|
95
|
+
readonly mount: (mount: ModuleMount) => CommandRegistry;
|
|
96
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The command this process is running, and the flags its line was parsed
|
|
3
|
+
* into.
|
|
4
|
+
*
|
|
5
|
+
* A reader deep below a command's `run` — the spend guard in
|
|
6
|
+
* `packages/rafa/src/core/loop/claude.ts` — asks {@link runningCommand} which command it
|
|
7
|
+
* runs under, without a context threaded down to it. The record is held
|
|
8
|
+
* in two places, and the reader answers the first that has one.
|
|
9
|
+
*
|
|
10
|
+
* ## The scope
|
|
11
|
+
*
|
|
12
|
+
* {@link runAsRunningCommand} runs a function with a record in an async
|
|
13
|
+
* scope of its own, an `AsyncLocalStorage` (`node:async_hooks`). Inside
|
|
14
|
+
* that function, and in everything it awaits or starts, the reader
|
|
15
|
+
* answers that record; once the function ends, however it ends, nothing
|
|
16
|
+
* of it is left. The dispatcher runs every command this way
|
|
17
|
+
* (`src/cli/dispatch.ts`), so nothing it records outlives the
|
|
18
|
+
* invocation.
|
|
19
|
+
*
|
|
20
|
+
* A scope belongs to one run, so runs need not nest to stay apart. Two
|
|
21
|
+
* runs that overlap in one process, started together and awaited with
|
|
22
|
+
* `Promise.all`, each read their own record whichever ends first. A run
|
|
23
|
+
* started inside another reads the inner record inside and the outer one
|
|
24
|
+
* after. The module-level value below keeps overlapping runs apart only
|
|
25
|
+
* while they nest: set and put back in a `finally` it is a stack, and
|
|
26
|
+
* two that end out of order leave the record of one of them for the
|
|
27
|
+
* rest of the process (#927).
|
|
28
|
+
*
|
|
29
|
+
* ## The module-level value
|
|
30
|
+
*
|
|
31
|
+
* {@link setRunningCommand} records a command with its parsed flags at
|
|
32
|
+
* module level and answers the record it replaced, null when nothing was
|
|
33
|
+
* recorded. {@link restoreRunningCommand} puts back a record
|
|
34
|
+
* {@link setRunningCommand} answered, so a caller that sets one restores
|
|
35
|
+
* it in a `finally`. Outside every scope the reader answers this value,
|
|
36
|
+
* or null. No module but a test sets it: a case stands in for a dispatch
|
|
37
|
+
* with it, as `src/tests/core-coupled/core/loop/claude.test.ts` does ahead of a door.
|
|
38
|
+
*
|
|
39
|
+
* ## A set made inside a scope
|
|
40
|
+
*
|
|
41
|
+
* The reader prefers the scope, and the setters write the module-level
|
|
42
|
+
* value alone, inside a scope as outside one. So a set made inside a
|
|
43
|
+
* scope changes nothing that scope reads, answers the module-level
|
|
44
|
+
* record it replaced, and is what the reader answers once the scope has
|
|
45
|
+
* ended. A scope's record cannot be replaced from inside it.
|
|
46
|
+
*
|
|
47
|
+
* ## What reads outside the scope
|
|
48
|
+
*
|
|
49
|
+
* A scope follows the awaits and the callbacks started inside it. A
|
|
50
|
+
* callback the runtime calls from elsewhere does not carry it. Measured
|
|
51
|
+
* under bun 1.3.14, three listeners registered inside a scope read no
|
|
52
|
+
* store: a `process.on` signal listener when the signal arrived, an
|
|
53
|
+
* abort listener that handler fired, and an abort listener an
|
|
54
|
+
* `AbortSignal.timeout` fired. A timer, a child process's `data`
|
|
55
|
+
* listener, a `readline` `line` listener and the code after an await
|
|
56
|
+
* such a handler settled all read the scope's. A reader outside the
|
|
57
|
+
* scope gets the module-level value; one that needs the scope's is
|
|
58
|
+
* wrapped with `AsyncResource.bind` where it is registered.
|
|
59
|
+
*
|
|
60
|
+
* The flags are copied and frozen when recorded, so a caller changing
|
|
61
|
+
* its own flags object afterwards changes nothing recorded.
|
|
62
|
+
*
|
|
63
|
+
* Bun runs every test file in one process, and the module-level value is
|
|
64
|
+
* module state: a case that sets a record restores the one it replaced
|
|
65
|
+
* after it.
|
|
66
|
+
*/
|
|
67
|
+
import type { RafaCommand } from './command.js';
|
|
68
|
+
import type { CliContext } from './types.js';
|
|
69
|
+
/** A running command and the flags its line was parsed into. */
|
|
70
|
+
export interface RunningCommand {
|
|
71
|
+
/** The command running. */
|
|
72
|
+
readonly command: RafaCommand;
|
|
73
|
+
/** Its parsed flags by name, as the context carries them. */
|
|
74
|
+
readonly flags: CliContext['flags'];
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Runs `run` with `command` and `flags` recorded as running in an async
|
|
78
|
+
* scope of its own, and answers what `run` answers. The record is read
|
|
79
|
+
* inside `run` and whatever it awaits, and nowhere after it; see the
|
|
80
|
+
* module note.
|
|
81
|
+
*/
|
|
82
|
+
export declare function runAsRunningCommand<T>(command: RafaCommand, flags: CliContext['flags'], run: () => T): T;
|
|
83
|
+
/**
|
|
84
|
+
* Records `command` as running with `flags` at module level, and answers
|
|
85
|
+
* the module-level record it replaced for {@link restoreRunningCommand}.
|
|
86
|
+
* Inside a scope it changes nothing that scope reads; see the module
|
|
87
|
+
* note.
|
|
88
|
+
*/
|
|
89
|
+
export declare function setRunningCommand(command: RafaCommand, flags: CliContext['flags']): RunningCommand | null;
|
|
90
|
+
/**
|
|
91
|
+
* The command running now with its flags: the record of the scope this
|
|
92
|
+
* is read in, else the module-level one, else null.
|
|
93
|
+
*/
|
|
94
|
+
export declare function runningCommand(): RunningCommand | null;
|
|
95
|
+
/** Puts back `previous`, a module-level record {@link setRunningCommand} answered. */
|
|
96
|
+
export declare function restoreRunningCommand(previous: RunningCommand | null): void;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/** The mark help puts on a command that spends Claude usage. */
|
|
2
|
+
export declare const SPENDS_GLYPH = "\uD83E\uDE99";
|
|
3
|
+
/** The four values `when` takes. */
|
|
4
|
+
export declare const SPENDS_WHEN: readonly ["always", "with", "unless", "through"];
|
|
5
|
+
/** One of the four forms of a declaration. */
|
|
6
|
+
export type SpendsWhen = (typeof SPENDS_WHEN)[number];
|
|
7
|
+
/** What a command spends, and when; see the module note. */
|
|
8
|
+
export type CommandSpend = {
|
|
9
|
+
readonly when: 'always';
|
|
10
|
+
readonly what: string;
|
|
11
|
+
} | {
|
|
12
|
+
readonly when: 'with';
|
|
13
|
+
readonly flag: string;
|
|
14
|
+
readonly what: string;
|
|
15
|
+
} | {
|
|
16
|
+
readonly when: 'unless';
|
|
17
|
+
readonly flag: string;
|
|
18
|
+
readonly what: string;
|
|
19
|
+
} | {
|
|
20
|
+
readonly when: 'through';
|
|
21
|
+
readonly what: string;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* What keeps `value` from being a `spends` declaration, as a sentence
|
|
25
|
+
* naming the field, or null when nothing does. Absent passes: a command
|
|
26
|
+
* that declares nothing spends nothing.
|
|
27
|
+
*/
|
|
28
|
+
export declare function spendsProblem(value: unknown): string | null;
|
|
29
|
+
/**
|
|
30
|
+
* The condition a declaration spends under, as help prints it:
|
|
31
|
+
* `with --resolve`, `unless --no-model`, or null for `always` and
|
|
32
|
+
* `through`.
|
|
33
|
+
*/
|
|
34
|
+
export declare function spendsCondition(spend: CommandSpend): string | null;
|
|
35
|
+
/**
|
|
36
|
+
* The mark ending a spender's roster line: `🪙`, `🪙 with --resolve` or
|
|
37
|
+
* `🪙 unless --no-model`.
|
|
38
|
+
*/
|
|
39
|
+
export declare function spendsMark(spend: CommandSpend): string;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The contracts a rafa command is written against: the context it runs
|
|
3
|
+
* with, the positional arguments and flags it declares, and the command.
|
|
4
|
+
*
|
|
5
|
+
* Copied from open-tomato's `packages/shared/cli-core/src/types.ts` at
|
|
6
|
+
* commit `6c774b81fc62489f31748c47e251f11448e3904a` (2026-06-25). The
|
|
7
|
+
* package is not on the public registry, so rafa copies it rather than
|
|
8
|
+
* depending on it, as it copies `parseArgs.ts` and `assembleContext.ts`,
|
|
9
|
+
* which stay in `src/cli/core/`, from the same package.
|
|
10
|
+
*
|
|
11
|
+
* The copy sat beside those two until it moved into `packages/rafa/src/core/command/`,
|
|
12
|
+
* so core's `command.ts` reads it without importing the CLI.
|
|
13
|
+
* `packages/rafa/src/core/command/index.ts` exports its names to every
|
|
14
|
+
* file outside core; the re-export `src/cli/core/types.ts` kept for the
|
|
15
|
+
* CLI was deleted when core moved into its package (#1090).
|
|
16
|
+
*
|
|
17
|
+
* ## What the copy changes
|
|
18
|
+
*
|
|
19
|
+
* `CliContext.output` is rafa's `Output` port, which `packages/rafa/src/ports/index.ts`
|
|
20
|
+
* copies from the source's `CliOutput`. The source imports that type from
|
|
21
|
+
* its own `output.ts`, whose two renderers rafa ported to
|
|
22
|
+
* `packages/rafa/src/core/output/text.ts` and `src/adapters/output/json.ts`. Every member is otherwise the source's, with a
|
|
23
|
+
* TSDoc line added to each.
|
|
24
|
+
*
|
|
25
|
+
* `ArgSpec` and `FlagSpec` are still two names for one shape. The source
|
|
26
|
+
* declares `default` and `aliases` on both and reads neither. The copy's
|
|
27
|
+
* `parseArgs` reads a flag's `default` and `aliases` and an argument's
|
|
28
|
+
* `default`, and refuses an argument that declares `aliases`, as its
|
|
29
|
+
* module note says.
|
|
30
|
+
*/
|
|
31
|
+
import type { Output } from '../../ports/index.js';
|
|
32
|
+
import type { OutputMode } from '../config/config-sections.js';
|
|
33
|
+
/** Everything a command runs with, built and frozen by `assembleContext`. */
|
|
34
|
+
export interface CliContext {
|
|
35
|
+
/** The positional words of the line, in order. */
|
|
36
|
+
args: readonly string[];
|
|
37
|
+
/** The flags of the line by name: a value, `true` for a bare flag, `false` for `--no-<name>`. */
|
|
38
|
+
flags: Readonly<Record<string, string | boolean>>;
|
|
39
|
+
/** How the command's output is rendered: lines a person reads, NDJSON events, or one line per loop event. */
|
|
40
|
+
outputMode: OutputMode;
|
|
41
|
+
/** How much the command writes, from 0, the least, to 3. */
|
|
42
|
+
verbosity: 0 | 1 | 2 | 3;
|
|
43
|
+
/** Where the command writes, rendered in its `outputMode`. */
|
|
44
|
+
output: Output;
|
|
45
|
+
/** Aborted when the command is asked to stop. */
|
|
46
|
+
signal: AbortSignal;
|
|
47
|
+
/** The environment the context was built from, as a frozen copy. */
|
|
48
|
+
env: Readonly<Record<string, string | undefined>>;
|
|
49
|
+
}
|
|
50
|
+
/** A positional argument a command declares. */
|
|
51
|
+
export interface ArgSpec {
|
|
52
|
+
/** What the argument is called. */
|
|
53
|
+
name: string;
|
|
54
|
+
/** What the argument holds, in a sentence. */
|
|
55
|
+
description: string;
|
|
56
|
+
/** The value's type. `parseArgs` converts no word to it: every word is a string. */
|
|
57
|
+
type: 'string' | 'boolean' | 'number';
|
|
58
|
+
/** Whether the command needs the argument. `parseArgs` refuses no line leaving it out. */
|
|
59
|
+
required?: boolean;
|
|
60
|
+
/** The word filled in when the line leaves the argument out, as a string. */
|
|
61
|
+
default?: string | boolean | number;
|
|
62
|
+
/** Refused by `parseArgs` when it names any: a positional word has no spelling but its place. */
|
|
63
|
+
aliases?: readonly string[];
|
|
64
|
+
}
|
|
65
|
+
/** A flag a command declares. */
|
|
66
|
+
export interface FlagSpec {
|
|
67
|
+
/** The flag's name, which `CliContext.flags` is keyed by: `plan` for `--plan`. */
|
|
68
|
+
name: string;
|
|
69
|
+
/** What the flag does, in a sentence. */
|
|
70
|
+
description: string;
|
|
71
|
+
/** The value's type. `parseArgs` converts no value to it: a value is a string. */
|
|
72
|
+
type: 'string' | 'boolean' | 'number';
|
|
73
|
+
/** Whether the command needs the flag. `parseArgs` refuses no line leaving it out. */
|
|
74
|
+
required?: boolean;
|
|
75
|
+
/** The value filled in when the line gives the flag none: a number as its string, anything else as it is. */
|
|
76
|
+
default?: string | boolean | number;
|
|
77
|
+
/** Other spellings of the flag, each read as its name: `p` reads `-p` and `--p` as `plan`. */
|
|
78
|
+
aliases?: readonly string[];
|
|
79
|
+
}
|
|
80
|
+
/** A command: what it declares, and what runs. */
|
|
81
|
+
export interface CliCommand {
|
|
82
|
+
/** The command's name. */
|
|
83
|
+
name: string;
|
|
84
|
+
/** What the command does. */
|
|
85
|
+
description: string;
|
|
86
|
+
/** The positional arguments, in the order the line gives them. */
|
|
87
|
+
args: ArgSpec[];
|
|
88
|
+
/** The flags. */
|
|
89
|
+
flags: FlagSpec[];
|
|
90
|
+
/** Runs the command with the context built for it. */
|
|
91
|
+
run: (context: CliContext) => Promise<void>;
|
|
92
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The glob matching every plan branch the template names: the template
|
|
3
|
+
* with `{stub}` replaced by `rafa-*`.
|
|
4
|
+
*
|
|
5
|
+
* @param template - A `naming.branch` template, such as `feat/{stub}`.
|
|
6
|
+
* @returns The glob, `feat/rafa-*` for the default template.
|
|
7
|
+
*/
|
|
8
|
+
export declare function branchGlob(template: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* The stub a branch carries under the template: what lies between the
|
|
11
|
+
* template's part before `{stub}` and its part after, when the branch
|
|
12
|
+
* opens with the one, closes with the other, and the stub between opens
|
|
13
|
+
* with `rafa-`.
|
|
14
|
+
*
|
|
15
|
+
* @param template - A `naming.branch` template, such as `feat/{stub}`.
|
|
16
|
+
* @param branch - A branch name, without `refs/heads/`.
|
|
17
|
+
* @returns The stub, `rafa-12-x` for `feat/rafa-12-x` under the default
|
|
18
|
+
* template; null for a branch the template does not name.
|
|
19
|
+
*/
|
|
20
|
+
export declare function stubOfBranch(template: string, branch: string): string | null;
|