@okfit/cli 0.1.0 → 0.2.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 +332 -3
- package/bin/okfit.js +47 -4
- package/commands/context.js +78 -0
- package/commands/init.js +177 -0
- package/commands/root.js +26 -3
- package/commands/sync.js +111 -0
- package/commands/validate.js +98 -0
- package/commands/verify.js +98 -0
- package/config/anchor.js +57 -0
- package/config/layer.js +129 -0
- package/config/resolve.js +67 -0
- package/context/run.js +35 -0
- package/errors.js +173 -0
- package/index.d.ts +891 -6
- package/index.js +15 -10
- package/init/scaffold.js +174 -0
- package/internal/exit.js +14 -0
- package/internal/tty.js +13 -0
- package/package.js +5 -0
- package/package.json +17 -5
- package/render/context.js +108 -0
- package/render/exit.js +53 -0
- package/render/human.js +68 -0
- package/render/json.js +126 -0
- package/render/sort.js +46 -0
- package/render/sync.js +101 -0
- package/render/verify.js +72 -0
- package/sync/generated.js +111 -0
- package/sync/index.js +73 -0
- package/sync/log.js +127 -0
- package/sync/run.js +65 -0
- package/sync/write.js +48 -0
- package/validate/run.js +63 -0
- package/verify/locate.js +249 -0
- package/verify/run.js +106 -0
- package/verify/splice.js +75 -0
- package/version.js +14 -0
package/index.d.ts
CHANGED
|
@@ -1,19 +1,904 @@
|
|
|
1
|
+
import { ConfigReadError, ConfigReadError as ConfigReadError$1 } from "@effected/config-file";
|
|
2
|
+
import { Context, DateTime, Effect, FileSystem, Layer, Option, Path, PlatformError, Runtime, Schema } from "effect";
|
|
3
|
+
import { Git, GitCommandError, UnknownRefError } from "@effected/git";
|
|
4
|
+
import { BundleLoadError, Diagnostic, DiagnosticRange, DiagnosticSeverity, LoadedBundle, OkfitConfig, OkfitConfigFile, ValidationReport } from "@okfit/core";
|
|
5
|
+
import { GitHistory, GitHistoryError, Layout, Profile, ProfileDiagnostic } from "@okfit/profiles";
|
|
1
6
|
import { Command } from "effect/unstable/cli";
|
|
7
|
+
import { AppDirs, Xdg } from "@effected/xdg";
|
|
8
|
+
import { FrontmatterWriteError, MarkdownParseError } from "@effected/markdown";
|
|
9
|
+
//#region src/errors.d.ts
|
|
10
|
+
declare const ConfigPathNotFoundError_base: Schema.Class<ConfigPathNotFoundError, Schema.TaggedStruct<"ConfigPathNotFoundError", {
|
|
11
|
+
readonly path: Schema.String;
|
|
12
|
+
}>, import("effect/Cause").YieldableError>;
|
|
13
|
+
/**
|
|
14
|
+
* `--config <path>` named a path that does not exist. Every `ConfigResolver`
|
|
15
|
+
* has a `never` error channel and `explicitPath` absorbs a missing target
|
|
16
|
+
* into `Option.none()`, so a bad `--config` would otherwise fall through to
|
|
17
|
+
* the XDG file silently. The CLI checks it itself before building any layer
|
|
18
|
+
* (K-1, spec 4.1).
|
|
19
|
+
*
|
|
20
|
+
* @public
|
|
21
|
+
*/
|
|
22
|
+
export declare class ConfigPathNotFoundError extends ConfigPathNotFoundError_base {
|
|
23
|
+
readonly [Runtime.errorExitCode] = 3;
|
|
24
|
+
get message(): string;
|
|
25
|
+
}
|
|
26
|
+
declare const InitOverwriteError_base: Schema.Class<InitOverwriteError, Schema.TaggedStruct<"InitOverwriteError", {
|
|
27
|
+
readonly paths: Schema.$Array<Schema.String>;
|
|
28
|
+
readonly cwd: Schema.String;
|
|
29
|
+
}>, import("effect/Cause").YieldableError>;
|
|
30
|
+
/**
|
|
31
|
+
* `okfit init` found one or more of its target paths already present (K-28).
|
|
32
|
+
* Carries the whole conflicting-path list so the renderer prints every one.
|
|
33
|
+
* `paths` are absolute; `renderFailure` relativises them to `cwd` (K-51).
|
|
34
|
+
*
|
|
35
|
+
* @public
|
|
36
|
+
*/
|
|
37
|
+
export declare class InitOverwriteError extends InitOverwriteError_base {
|
|
38
|
+
readonly [Runtime.errorExitCode] = 3;
|
|
39
|
+
get message(): string;
|
|
40
|
+
}
|
|
41
|
+
declare const VerifyConceptNotFoundError_base: Schema.Class<VerifyConceptNotFoundError, Schema.TaggedStruct<"VerifyConceptNotFoundError", {
|
|
42
|
+
readonly id: Schema.String;
|
|
43
|
+
readonly root: Schema.String;
|
|
44
|
+
readonly reason: Schema.Literals<readonly ["not-a-concept", "reserved", "undecodable"]>;
|
|
45
|
+
readonly diagnosticCode: Schema.optionalKey<Schema.String>;
|
|
46
|
+
}>, import("effect/Cause").YieldableError>;
|
|
47
|
+
/**
|
|
48
|
+
* V-9: `<id>` did not resolve to a verifiable concept. `reason` is
|
|
49
|
+
* `"not-a-concept"` (no such file, or an id that normalises to nothing),
|
|
50
|
+
* `"reserved"` (the id names `index.md` or `log.md`), or `"undecodable"`
|
|
51
|
+
* (a file exists but `bundle.diagnostics` names it — `diagnosticCode`
|
|
52
|
+
* carries which). `root` is the absolute bundle root, kept OFF `message`
|
|
53
|
+
* so K-51's relativisation rule has nothing to apply to and the human
|
|
54
|
+
* line and the JSON envelope's `message` are identical.
|
|
55
|
+
*
|
|
56
|
+
* @public
|
|
57
|
+
*/
|
|
58
|
+
export declare class VerifyConceptNotFoundError extends VerifyConceptNotFoundError_base {
|
|
59
|
+
readonly [Runtime.errorExitCode] = 3;
|
|
60
|
+
get message(): string;
|
|
61
|
+
}
|
|
62
|
+
declare const VerifyUnsupportedFrontmatterError_base: Schema.Class<VerifyUnsupportedFrontmatterError, Schema.TaggedStruct<"VerifyUnsupportedFrontmatterError", {
|
|
63
|
+
readonly id: Schema.String;
|
|
64
|
+
readonly shape: Schema.String;
|
|
65
|
+
}>, import("effect/Cause").YieldableError>;
|
|
66
|
+
/**
|
|
67
|
+
* V-14: fail closed on a `verified` shape the classifier does not name.
|
|
68
|
+
* `shape` is one of `"alias"`, `"merge-key"`, `"scalar"`, `"empty"` (and,
|
|
69
|
+
* defensively, `"no-frontmatter"` or `"not-a-mapping"`, neither reachable
|
|
70
|
+
* for a concept that reached `bundle.concepts`). The file is never opened
|
|
71
|
+
* for writing when this is raised.
|
|
72
|
+
*
|
|
73
|
+
* @public
|
|
74
|
+
*/
|
|
75
|
+
export declare class VerifyUnsupportedFrontmatterError extends VerifyUnsupportedFrontmatterError_base {
|
|
76
|
+
readonly [Runtime.errorExitCode] = 3;
|
|
77
|
+
get message(): string;
|
|
78
|
+
}
|
|
79
|
+
declare const ConfigMalformedError_base: Schema.Class<ConfigMalformedError, Schema.TaggedStruct<"ConfigMalformedError", {
|
|
80
|
+
readonly path: Schema.String;
|
|
81
|
+
readonly cause: Schema.Defect;
|
|
82
|
+
}>, import("effect/Cause").YieldableError>;
|
|
83
|
+
/**
|
|
84
|
+
* A config file at a KNOWN path failed to parse or validate (K-46's own
|
|
85
|
+
* intent — "each class' message already names the offending path" does not
|
|
86
|
+
* hold for `@effected/config-file`'s `ConfigCodecError`, which carries no
|
|
87
|
+
* `path` field at all; this wraps it, and `ConfigValidationError`, with the
|
|
88
|
+
* path the caller already knows). `cause` is the original config-file error,
|
|
89
|
+
* preserved structurally, never stringified early.
|
|
90
|
+
*
|
|
91
|
+
* @public
|
|
92
|
+
*/
|
|
93
|
+
export declare class ConfigMalformedError extends ConfigMalformedError_base {
|
|
94
|
+
readonly [Runtime.errorExitCode] = 3;
|
|
95
|
+
get message(): string;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* The `render` option for `CliRuntime.reportFailures` (K-30, K-46, K-51). One
|
|
99
|
+
* string per stderr line; `reportFailures` emits each through its own
|
|
100
|
+
* `Effect.logError`, which `CliLogger` routes to stderr.
|
|
101
|
+
*
|
|
102
|
+
* Rules, in order:
|
|
103
|
+
*
|
|
104
|
+
* 1. A `ShowHelp` (any `_tag === "ShowHelp"`) renders as `[]` — the empty
|
|
105
|
+
* array. `Command.runWith` has already rendered the help document and any
|
|
106
|
+
* parse errors before re-failing, so a second rendering here would print
|
|
107
|
+
* "Help requested" after the help text. This is why the K-30 remap in
|
|
108
|
+
* `bin.ts` can run ahead of `reportFailures` without corrupting `--help`
|
|
109
|
+
* output.
|
|
110
|
+
* 2. `ConfigPathNotFoundError` renders as its own `error: <message>` line;
|
|
111
|
+
* `InitOverwriteError` renders as the K-51 header, one two-space-indented
|
|
112
|
+
* relativised path per conflict, and the literal `Nothing was written.`.
|
|
113
|
+
* 3. `ConfigMalformedError` renders as its own `error: <message>` line —
|
|
114
|
+
* `error: malformed config <path>: <cause message>` — since it already
|
|
115
|
+
* carries the offending path (`config/layer.ts#provideConfig` wraps a
|
|
116
|
+
* `ConfigCodecError`/`ConfigValidationError` into this the moment the
|
|
117
|
+
* path is known).
|
|
118
|
+
* 4. A `ConfigValidationError` NOT already wrapped above (detected by
|
|
119
|
+
* `_tag`, since the peer is optional and this module keeps it a
|
|
120
|
+
* type-only import — this is the "path unknown" case, K-46) renders as
|
|
121
|
+
* `error: ${String(error)}` followed by one two-space-indented
|
|
122
|
+
* `ConfigIssueRenderer.render(error)` line per entry.
|
|
123
|
+
* 5. `VerifyConceptNotFoundError` and `VerifyUnsupportedFrontmatterError`
|
|
124
|
+
* each render as their own `error: <message>` line; both messages
|
|
125
|
+
* already name the concept id and what to do about it, and neither
|
|
126
|
+
* carries a filesystem path needing K-51 relativisation.
|
|
127
|
+
* 6. Everything else — core's `BundleRootNotFoundError`/`BundleReadError`/
|
|
128
|
+
* `BundleDepthExceededError`, config-file's other errors, `XdgEnvError`
|
|
129
|
+
* (the K-13 `HOME`-unset case) — renders as the single line
|
|
130
|
+
* `error: ${String(error)}`. Each of those
|
|
131
|
+
* classes' own `message` already names the offending path, which is all
|
|
132
|
+
* K-46 asserts.
|
|
133
|
+
*
|
|
134
|
+
* @public
|
|
135
|
+
*/
|
|
136
|
+
export declare const renderFailure: (error: unknown) => ReadonlyArray<string>;
|
|
137
|
+
//#endregion
|
|
138
|
+
//#region src/validate/run.d.ts
|
|
139
|
+
declare const Now_base: Context.ServiceClass<Now, "@okfit/cli/Now", DateTime.Utc>;
|
|
140
|
+
/**
|
|
141
|
+
* K-47's ambient clock. `bin.ts` resolves `OKFIT_NOW` (or the wall clock)
|
|
142
|
+
* exactly once and provides it with `Effect.provideService(Now, value)`
|
|
143
|
+
* around the whole command tree; `commands/validate.ts` and
|
|
144
|
+
* `commands/init.ts` each read it with `const now = yield* Now;` before
|
|
145
|
+
* building {@link RunOptions} or a scaffold's `today`. Not re-exported from
|
|
146
|
+
* `index.ts`: like `internal/exit.ts` and `internal/tty.ts`, it means
|
|
147
|
+
* nothing outside a spawned process (K-49). `Context.Tag` does not exist on
|
|
148
|
+
* the Effect v4 line; the v4 shape is
|
|
149
|
+
* `Context.Service<Self, Shape>()(id)`, the same form core and profiles use
|
|
150
|
+
* for their own services (`PROFILES/GitHistory.ts:140`) — source wins over
|
|
151
|
+
* the contract's literal snippet here (K-62).
|
|
152
|
+
*
|
|
153
|
+
* @internal
|
|
154
|
+
*/
|
|
155
|
+
declare class Now extends Now_base {}
|
|
156
|
+
/** @public */
|
|
157
|
+
interface RunOptions {
|
|
158
|
+
/** Absolute bundle root; `Bundle.load` never reads cwd (D-8). */
|
|
159
|
+
readonly root: string;
|
|
160
|
+
/** Already merged `DEFAULTS < profile < file` by the caller (D-28). */
|
|
161
|
+
readonly config: OkfitConfig;
|
|
162
|
+
/** The resolved profile, when `Profiles.get` found one. */
|
|
163
|
+
readonly profile: Option.Option<Profile>;
|
|
164
|
+
/** `OKFIT_NOW` or `DateTime.now`, from `bin.ts` (K-47); enables the `stale` rule (D-34). */
|
|
165
|
+
readonly now: DateTime.Utc;
|
|
166
|
+
/**
|
|
167
|
+
* S-31: skip `Provenance.lint`'s git tier for this one invocation,
|
|
168
|
+
* without touching the project's `[lint]` table. `commands/validate.ts`
|
|
169
|
+
* threads `--skip-provenance` here; the PostToolUse hook passes the flag
|
|
170
|
+
* so an edit-time `validate` stays git-free even when the config leaves
|
|
171
|
+
* `generated-at-drift` at its default severity. Defaults to `false`, and
|
|
172
|
+
* is checked the same way `severity === "off"` already is — `run` skips
|
|
173
|
+
* the walk when EITHER is true.
|
|
174
|
+
*/
|
|
175
|
+
readonly skipProvenance?: boolean;
|
|
176
|
+
}
|
|
177
|
+
/** @public */
|
|
178
|
+
interface RunResult {
|
|
179
|
+
readonly bundle: LoadedBundle;
|
|
180
|
+
readonly report: ValidationReport;
|
|
181
|
+
/** `[]` when `profile` is `None`. */
|
|
182
|
+
readonly profileDiagnostics: ReadonlyArray<ProfileDiagnostic>;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Load, validate both tiers, run the profile check, then — UNLESS the
|
|
186
|
+
* `generated-at-drift` lint is `off` OR `options.skipProvenance` is `true`
|
|
187
|
+
* — run `Provenance.lint` and append its `Diagnostic`s to `report.lint`.
|
|
188
|
+
* The "skip the git walk entirely" gate lives HERE, in `run`, not inside
|
|
189
|
+
* `Provenance.lint` (S-8's own wording): a bundle configured `off`, or a
|
|
190
|
+
* caller that passed `--skip-provenance`, never pays for a git spawn
|
|
191
|
+
* (S-31). An `error` severity on the appended diagnostics yields exit `1`
|
|
192
|
+
* through the EXISTING lint-tier rule in `render/exit.ts` — no renderer
|
|
193
|
+
* branch, no new `DiagnosticSource`, since these diagnostics flow through
|
|
194
|
+
* the same `report.lint` array every other core lint diagnostic already
|
|
195
|
+
* does.
|
|
196
|
+
*
|
|
197
|
+
* K-52 holds structurally: `Bundle.load`'s failure short-circuits the
|
|
198
|
+
* generator, so `profile.check` never runs on a bundle that did not load.
|
|
199
|
+
*
|
|
200
|
+
* This is a BREAKING signature change: `@okfit/mcp`'s `validateBundle.ts`
|
|
201
|
+
* calls this function directly and must be updated to match (Task C1);
|
|
202
|
+
* `commands/validate.ts` is the other caller.
|
|
203
|
+
*
|
|
204
|
+
* @public
|
|
205
|
+
*/
|
|
206
|
+
export declare const run: (options: RunOptions) => Effect.Effect<RunResult, BundleLoadError | GitHistoryError | GitCommandError | UnknownRefError | PlatformError.PlatformError, FileSystem.FileSystem | Path.Path | Git | GitHistory>;
|
|
207
|
+
//#endregion
|
|
2
208
|
//#region src/commands/root.d.ts
|
|
3
209
|
/**
|
|
4
|
-
*
|
|
210
|
+
* K-5. No handler: the framework's own default for a command with neither a
|
|
211
|
+
* `handle` nor a matched subcommand is
|
|
212
|
+
* `Effect.fail(new CliError.ShowHelp({ commandPath, errors: [] }))`, and a
|
|
213
|
+
* `ShowHelp` with no errors carries `[Runtime.errorExitCode] = 0`. Bare
|
|
214
|
+
* `okfit` therefore prints the root help and exits `0` with no code in this
|
|
215
|
+
* package at all.
|
|
216
|
+
*
|
|
217
|
+
* `validate`, `init`, `context`, `verify`, and `sync` are the whole command tree;
|
|
218
|
+
* nothing else is registered here. Each is appended in introduction order,
|
|
219
|
+
* never reordered in, so `--help`'s subcommand list reads that way too
|
|
220
|
+
* (contract §4.2). The top-level description is left unchanged: neither
|
|
221
|
+
* `context` nor `verify` validates or scaffolds, but widening the sentence
|
|
222
|
+
* for the orientation- and attestation-only commands buys nothing
|
|
223
|
+
* (contract §4.2).
|
|
224
|
+
*
|
|
225
|
+
* @public
|
|
226
|
+
*/
|
|
227
|
+
export declare const rootCommand: Command.Command<"okfit", {} | {}, {}, import("@okfit/profiles").AgentActorUnconfiguredError | import("@okfit/core").BundleDepthExceededError | import("@okfit/core").BundleReadError | import("@okfit/core").BundleRootNotFoundError | import("@effected/config-file").ConfigCodecError | import("@effected/config-file").ConfigFileReadError | ConfigMalformedError | ConfigPathNotFoundError | import("@effected/config-file").ConfigValidationError | import("@effected/markdown").FrontmatterEncodeError | import("@effected/markdown").FrontmatterFormatMismatchError | import("@effected/markdown").FrontmatterValidationError | import("@effected/git").GitCommandError | import("@okfit/profiles").GitHistoryError | import("@okfit/profiles").HumanActorUnresolvedError | InitOverwriteError | import("@effected/markdown").MarkdownParseError | import("@effected/git").NotARepositoryError | import("effect/PlatformError").PlatformError | import("effect/Schema").SchemaError | import("@effected/git").UnknownRefError | VerifyConceptNotFoundError | VerifyUnsupportedFrontmatterError | import("@effected/yaml").YamlParseError, import("@effected/xdg").AppDirs | import("effect/unstable/process/ChildProcessSpawner").ChildProcessSpawner | import("effect/FileSystem").FileSystem | Now | import("effect/Path").Path | import("@effected/xdg").Xdg>;
|
|
228
|
+
//#endregion
|
|
229
|
+
//#region src/config/anchor.d.ts
|
|
230
|
+
/**
|
|
231
|
+
* What {@link resolveProjectRoot} needs about the winning discovery source
|
|
232
|
+
* (K-12, K-58). Narrower than `@effected/config-file`'s own
|
|
233
|
+
* `ConfigSource`: only `path`, `resolver` and the match's `dir` matter for
|
|
234
|
+
* anchoring, and a caller building this from a real
|
|
235
|
+
* `ConfigSource<OkfitConfig>` simply drops `value`.
|
|
236
|
+
*
|
|
237
|
+
* @public
|
|
238
|
+
*/
|
|
239
|
+
interface DiscoveredConfig {
|
|
240
|
+
/** `ConfigSource.path` — absolute. */
|
|
241
|
+
readonly path: string;
|
|
242
|
+
/** `ConfigSource.resolver` — the resolver's `name`. */
|
|
243
|
+
readonly resolver: string;
|
|
244
|
+
/**
|
|
245
|
+
* `ConfigSource.match?.dir` — the ancestor directory `upwardWalk`
|
|
246
|
+
* anchored the winning candidate against. Absent when the resolver did
|
|
247
|
+
* not implement `resolveMatch`, or reported no `dir` (`explicitPath`
|
|
248
|
+
* never does, by design).
|
|
249
|
+
*/
|
|
250
|
+
readonly dir?: string;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* K-12's project root, as amended by K-58 and C1-2, in order:
|
|
254
|
+
*
|
|
255
|
+
* 1. `pathArg`, if given. `Argument.path` has already resolved it absolute.
|
|
256
|
+
* 2. otherwise, if `--config` was given: `anchorForExplicit` applied to that
|
|
257
|
+
* path.
|
|
258
|
+
* 3. otherwise, if a config was discovered by the `"project"` resolver
|
|
259
|
+
* (`ConfigResolver.upwardWalk`, named `"project"` in `layer.ts`) AND it
|
|
260
|
+
* reported a `dir`: that `dir` verbatim — it is already the ancestor
|
|
261
|
+
* `upwardWalk` anchored the match against (the parent of `.config` for a
|
|
262
|
+
* `.config/okfit.toml` candidate, the candidate's own directory
|
|
263
|
+
* otherwise), so no path-tail test is needed here any more.
|
|
264
|
+
* 4. otherwise `cwd` — this covers every other resolver name (`"xdg"`,
|
|
265
|
+
* `"native"`, `"system"`) as defence in depth, a `"project"` match with no
|
|
266
|
+
* `dir` (should not happen, since `upwardWalk` always reports one), and
|
|
267
|
+
* no discovery at all.
|
|
268
|
+
*
|
|
269
|
+
* The CLI never probes for `.git` (K-12), even though
|
|
270
|
+
* `ConfigResolver.gitRoot` exists.
|
|
271
|
+
*
|
|
272
|
+
* @public
|
|
273
|
+
*/
|
|
274
|
+
export declare const resolveProjectRoot: (input: {
|
|
275
|
+
readonly pathArg: Option.Option<string>;
|
|
276
|
+
readonly explicitConfigPath: Option.Option<string>;
|
|
277
|
+
readonly discovered: Option.Option<DiscoveredConfig>;
|
|
278
|
+
readonly cwd: string;
|
|
279
|
+
readonly path: Path.Path;
|
|
280
|
+
}) => string;
|
|
281
|
+
/**
|
|
282
|
+
* `<project root>/<bundle.path>`, absolute (K-2). `config` is the MERGED
|
|
283
|
+
* config, so `bundle.path` is `OkfitConfig.DEFAULTS.bundle.path` (`"okf"`)
|
|
284
|
+
* unless a file or profile overrode it. The bundle root is never what
|
|
285
|
+
* `[path]` names.
|
|
286
|
+
*
|
|
287
|
+
* @public
|
|
288
|
+
*/
|
|
289
|
+
export declare const resolveBundleRoot: (projectRoot: string, config: OkfitConfig, path: Path.Path) => string;
|
|
290
|
+
//#endregion
|
|
291
|
+
//#region src/config/layer.d.ts
|
|
292
|
+
/**
|
|
293
|
+
* The `OkfitConfigFile` layer for one invocation (K-9 to K-11, K-57, C-6),
|
|
294
|
+
* now one `AppConfig.layer(OkfitConfigFile, ...)` call in both branches; only
|
|
295
|
+
* the chain options vary:
|
|
296
|
+
*
|
|
297
|
+
* - `explicitConfigPath` is `Some`: `resolvers: [ConfigResolver.explicitPath(path)]`
|
|
298
|
+
* and `xdg: false` — K-10's "only that path" rule, so the chain is exactly
|
|
299
|
+
* one resolver and no `systemEtc` tier is added either.
|
|
300
|
+
* - `explicitConfigPath` is `None`: `resolvers: [ConfigResolver.upwardWalk({ filenames, ... })]`
|
|
301
|
+
* carrying C-1's three per-directory candidates (`.okfit.toml`,
|
|
302
|
+
* `okfit.toml`, `.config/okfit.toml`, directory-major so a child's later
|
|
303
|
+
* candidate beats a parent's earlier one — C-2's ascent to the filesystem
|
|
304
|
+
* root is `upwardWalk`'s own default with no `stopAt`), named `"project"`
|
|
305
|
+
* so `resolve.ts`/`anchor.ts` can identify it without string-matching a
|
|
306
|
+
* path tail. `systemEtc` is C-5's `/etc` tier, present unless
|
|
307
|
+
* `systemConfigDir` overrides its root (tests only — no production call
|
|
308
|
+
* site sets it). `xdg` and `native` stay on their defaults (C-4), which is
|
|
309
|
+
* what puts personal defaults at `$XDG_CONFIG_HOME/okfit/config.toml` and
|
|
310
|
+
* the native probe behind it.
|
|
311
|
+
*
|
|
312
|
+
* `filename: "config.toml"` is the same in both branches — it is the XDG/
|
|
313
|
+
* native/system tiers' filename, unrelated to the C-1 project names above.
|
|
314
|
+
* `defaultPath` is `AppConfig.layer`'s own `XdgConfig.savePath(filename)`, so
|
|
315
|
+
* `save`/`update` do not fail with `ConfigDefaultPathMissingError`; nothing
|
|
316
|
+
* here sets it explicitly any more.
|
|
317
|
+
*
|
|
318
|
+
* `discoveryCwd` is `[path]` when given, else `process.cwd()` (K-2), passed
|
|
319
|
+
* straight through as `upwardWalk`'s own `cwd` so nothing in this module
|
|
320
|
+
* reads the process.
|
|
321
|
+
*
|
|
322
|
+
* `App.layer`, `AppStore` and `AppCache` appear nowhere, so no
|
|
323
|
+
* `store.db`/`cache.db` is ever created (K-9).
|
|
324
|
+
*
|
|
325
|
+
* @public
|
|
326
|
+
*/
|
|
327
|
+
export declare const buildConfigLayer: (options: {
|
|
328
|
+
readonly explicitConfigPath: Option.Option<string>;
|
|
329
|
+
readonly discoveryCwd: string;
|
|
330
|
+
/**
|
|
331
|
+
* System config root, defaulting to `/etc`. Overridable primarily so tests
|
|
332
|
+
* can point at a writable temp directory — the real `/etc` is not writable
|
|
333
|
+
* in test environments. No production call site sets it.
|
|
334
|
+
*/
|
|
335
|
+
readonly systemConfigDir?: string;
|
|
336
|
+
}) => Layer.Layer<OkfitConfigFile, never, FileSystem.FileSystem | Path.Path | AppDirs | Xdg>;
|
|
337
|
+
/**
|
|
338
|
+
* The K-1 pre-flight and the provide, in that order and in one place: stat
|
|
339
|
+
* `explicitConfigPath` with `FileSystem.exists` and fail with
|
|
340
|
+
* `ConfigPathNotFoundError` BEFORE `buildConfigLayer` is called at all. This
|
|
341
|
+
* is why the CLI does not use `Command.provide(cmd, (input) => layer)`,
|
|
342
|
+
* which would construct the layer first (Judge notes 9) — here the stat
|
|
343
|
+
* runs as the first step of one `Effect.gen`, and `buildConfigLayer` is only
|
|
344
|
+
* reached, and only then actually run, on the step after it.
|
|
345
|
+
*
|
|
346
|
+
* `FileSystem.FileSystem.exists` is `(path: string) => Effect.Effect<boolean, PlatformError>`
|
|
347
|
+
* (`EF/FileSystem.ts:143-145`), not infallible, so
|
|
348
|
+
* `PlatformError.PlatformError` joins the error channel here (decision 7):
|
|
349
|
+
* an unusual stat failure (e.g. a permission error on a parent directory)
|
|
350
|
+
* renders through `renderFailure`'s catch-all rule rather than being
|
|
351
|
+
* uncatchable by the type checker.
|
|
352
|
+
*
|
|
353
|
+
* K-46/K-63 fix: a `ConfigCodecError`/`ConfigValidationError` from
|
|
354
|
+
* `buildConfigLayer`'s provided layer is wrapped into `ConfigMalformedError`
|
|
355
|
+
* whenever the failing path is known, so `renderFailure` can name it:
|
|
356
|
+
*
|
|
357
|
+
* - `ConfigCodecError` now carries its own `path: string | undefined`
|
|
358
|
+
* (config-file 0.7.0, `ConfigFile.discover` re-raises with `path` attached
|
|
359
|
+
* at every site that fed the codec a path it resolved) — used when
|
|
360
|
+
* present, so a malformed file found during DISCOVERY (no `--config`) now
|
|
361
|
+
* also wraps into `ConfigMalformedError` naming the candidate that failed,
|
|
362
|
+
* closing the K-63 gap. It falls back to `explicitConfigPath` only when
|
|
363
|
+
* the library's own `path` is `undefined` and `--config` was given; only
|
|
364
|
+
* when neither is known does the cause pass through unwrapped.
|
|
365
|
+
* - `ConfigValidationError` carries its own `path: Option<string>` — used
|
|
366
|
+
* when present (either branch), falling back to `explicitConfigPath` when
|
|
367
|
+
* the library's own `path` is `None` and `--config` was given.
|
|
368
|
+
*
|
|
369
|
+
* @public
|
|
370
|
+
*/
|
|
371
|
+
export declare const provideConfig: (options: {
|
|
372
|
+
readonly explicitConfigPath: Option.Option<string>;
|
|
373
|
+
readonly discoveryCwd: string;
|
|
374
|
+
readonly systemConfigDir?: string;
|
|
375
|
+
}) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E | ConfigPathNotFoundError | ConfigMalformedError | PlatformError.PlatformError, Exclude<R, OkfitConfigFile> | FileSystem.FileSystem | Path.Path | AppDirs | Xdg>;
|
|
376
|
+
//#endregion
|
|
377
|
+
//#region src/config/resolve.d.ts
|
|
378
|
+
/**
|
|
379
|
+
* `OkfitConfig.DEFAULTS.bundle.profile` is `"software-project"` at runtime
|
|
380
|
+
* (the frozen literal always sets it), but `bundle` and `profile` are both
|
|
381
|
+
* `optionalKey` in the schema, so the type checker sees `string | undefined`
|
|
382
|
+
* two levels deep. The `?? "software-project"` fallback here is unreachable
|
|
383
|
+
* in practice; it exists only to satisfy `noUncheckedIndexedAccess`-style
|
|
384
|
+
* strictness without a non-null assertion. Formerly duplicated identically
|
|
385
|
+
* in `commands/validate.ts` and `commands/context.ts`; this is its one home
|
|
386
|
+
* now that both commands delegate to {@link resolveProjectConfig}.
|
|
387
|
+
*
|
|
388
|
+
* @public
|
|
389
|
+
*/
|
|
390
|
+
export declare const DEFAULT_PROFILE_NAME: string;
|
|
391
|
+
/**
|
|
392
|
+
* Everything `validate` and `context`'s handlers derive from config
|
|
393
|
+
* discovery before diverging (contract §8.3): the merged config, the
|
|
394
|
+
* resolved profile (and its name after the "none"/default rule), the
|
|
395
|
+
* discovery source (if any), and the project/bundle roots.
|
|
396
|
+
*
|
|
397
|
+
* @public
|
|
398
|
+
*/
|
|
399
|
+
interface ResolvedProjectConfig {
|
|
400
|
+
readonly projectRoot: string;
|
|
401
|
+
readonly bundleRoot: string;
|
|
402
|
+
readonly config: OkfitConfig;
|
|
403
|
+
readonly profile: Option.Option<Profile>;
|
|
404
|
+
readonly profileName: string;
|
|
405
|
+
readonly discovered: Option.Option<DiscoveredConfig>;
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Input to {@link resolveProjectConfig}: the same three values every command
|
|
409
|
+
* handler already has in hand (its own `[path]` argument, its own
|
|
410
|
+
* `--config` flag, and `process.cwd()`) — nothing this function needs is
|
|
411
|
+
* read from `process` itself.
|
|
412
|
+
*
|
|
413
|
+
* @public
|
|
414
|
+
*/
|
|
415
|
+
interface ResolveProjectConfigInput {
|
|
416
|
+
readonly pathArg: Option.Option<string>;
|
|
417
|
+
readonly explicitConfigPath: Option.Option<string>;
|
|
418
|
+
readonly cwd: string;
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* The config-resolution step byte-identical between `validate` and
|
|
422
|
+
* `context`'s handlers (A2 review finding): discover, pick `sources[0]`,
|
|
423
|
+
* default `{ extensions: {} }`, resolve the profile name and the K-4
|
|
424
|
+
* unknown-profile warning, merge `DEFAULTS < profile < file` (D-28), warn on
|
|
425
|
+
* an `okf_version` mismatch (K-15), then resolve the project and bundle
|
|
426
|
+
* roots (K-12). Every message string and the merge order are unchanged from
|
|
427
|
+
* the two commands' former inline copies.
|
|
428
|
+
*
|
|
429
|
+
* @public
|
|
430
|
+
*/
|
|
431
|
+
export declare const resolveProjectConfig: (input: ResolveProjectConfigInput) => Effect.Effect<ResolvedProjectConfig, ConfigReadError$1, OkfitConfigFile | Path.Path>;
|
|
432
|
+
//#endregion
|
|
433
|
+
//#region src/context/run.d.ts
|
|
434
|
+
/** @public */
|
|
435
|
+
interface ContextRunOptions {
|
|
436
|
+
readonly bundleRoot: string;
|
|
437
|
+
}
|
|
438
|
+
/** @public */
|
|
439
|
+
interface ContextResult {
|
|
440
|
+
readonly indexPath: string;
|
|
441
|
+
readonly indexExists: boolean;
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* The whole of `context`'s filesystem work: join `index.md` onto the bundle
|
|
445
|
+
* root and stat it. Loading a bundle and running conformance/lint checks
|
|
446
|
+
* over it never happen here — that is what makes `context` cheap enough
|
|
447
|
+
* for a hook to run on every session start and every in-bundle write
|
|
448
|
+
* (M-15).
|
|
449
|
+
*
|
|
450
|
+
* `"index.md"` is a literal here, not read from the profile's layout: the
|
|
451
|
+
* spec fixes the reserved filename regardless of profile, and a
|
|
452
|
+
* profile-less merge (`profile = "none"`) has no layout to read from at
|
|
453
|
+
* all — `context` behaves identically with and without a profile.
|
|
454
|
+
*
|
|
455
|
+
* `exists` is `(path) => Effect.Effect<boolean, PlatformError>`, so an
|
|
456
|
+
* unreadable parent directory would otherwise fail the command; here it is
|
|
457
|
+
* absorbed to `false`, because "the hook could not stat index.md" and
|
|
458
|
+
* "index.md is not there" are the same fact from a consumer's point of
|
|
459
|
+
* view.
|
|
460
|
+
*
|
|
461
|
+
* @public
|
|
462
|
+
*/
|
|
463
|
+
export declare const runContext: (options: ContextRunOptions) => Effect.Effect<ContextResult, never, FileSystem.FileSystem | Path.Path>;
|
|
464
|
+
//#endregion
|
|
465
|
+
//#region src/init/scaffold.d.ts
|
|
466
|
+
/** `.config/okfit.toml`, relative to the project root (C-10). @public */
|
|
467
|
+
export declare const CONFIG_RELATIVE_PATH = ".config/okfit.toml";
|
|
468
|
+
/** @public */
|
|
469
|
+
interface ScaffoldOptions {
|
|
470
|
+
/** Absolute. */
|
|
471
|
+
readonly projectRoot: string;
|
|
472
|
+
/** Absolute; `<projectRoot>/<bundle.path>`. */
|
|
473
|
+
readonly bundleRoot: string;
|
|
474
|
+
/** The resolved profile's `layout` (`PROFILES/Profile.ts:35-38`, P-26). */
|
|
475
|
+
readonly layout: Layout;
|
|
476
|
+
/** The name written into the config and the log entry. */
|
|
477
|
+
readonly profileName: string;
|
|
478
|
+
/** `basename(projectRoot)` — `project.md`'s `title` (K-26). */
|
|
479
|
+
readonly projectTitle: string;
|
|
480
|
+
/** `YYYY-MM-DD`, derived from the CLI's `now` (K-25, K-47). */
|
|
481
|
+
readonly today: string;
|
|
482
|
+
}
|
|
483
|
+
/** One file `init` will write. Pure data; this module imports no `FileSystem`. @public */
|
|
484
|
+
interface ScaffoldFile {
|
|
485
|
+
/** Absolute. */
|
|
486
|
+
readonly path: string;
|
|
487
|
+
readonly contents: string;
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* K-23: the THIN override only — never the merged config. `bundle.path` is
|
|
491
|
+
* the bundle root relative to the project root; `extensions: {}` satisfies
|
|
492
|
+
* `OkfitConfig`'s one non-optional field (`CORE/OkfitConfig.ts:164`).
|
|
493
|
+
* Everything else resolves from `DEFAULTS` and the profile at load time.
|
|
494
|
+
* `actors.agent` is deliberately absent (K-24, P-17).
|
|
495
|
+
*
|
|
496
|
+
* @public
|
|
497
|
+
*/
|
|
498
|
+
export declare const configValue: (options: ScaffoldOptions & {
|
|
499
|
+
readonly bundlePath: string;
|
|
500
|
+
}) => OkfitConfig;
|
|
501
|
+
/**
|
|
502
|
+
* Every path `init` will create, absolute, in write order, for the K-28
|
|
503
|
+
* pre-flight: the three project-level config names, the bundle root's
|
|
504
|
+
* `index.md`/`log.md`/`project.md`, then one `index.md` per layout directory
|
|
505
|
+
* in `layout`'s own declared order — never re-sorted here. `Derive.renderIndex`
|
|
506
|
+
* sorts its own `Subdirectories` section independently (C13), so this
|
|
507
|
+
* function's order has no bearing on the rendered index text.
|
|
508
|
+
*
|
|
509
|
+
* @public
|
|
510
|
+
*/
|
|
511
|
+
export declare const targetPaths: (options: ScaffoldOptions) => ReadonlyArray<string>;
|
|
512
|
+
/**
|
|
513
|
+
* The three root markdown files and the per-directory indexes (K-25 to
|
|
514
|
+
* K-27, K-59). `project.md`'s frontmatter is written with
|
|
515
|
+
* `MarkdownFrontmatter.setToString` — the INSERT path, since the body below
|
|
516
|
+
* carries no frontmatter block of its own (`MD/index.d.ts:1959`,
|
|
517
|
+
* `FrontmatterWriteError`'s own doc comment: "a document with no frontmatter
|
|
518
|
+
* capture is the insert path, not an error"). The root `index.md` is
|
|
519
|
+
* `Derive.renderIndex` over a `LoadedConcept` this function synthesizes from
|
|
520
|
+
* the just-rendered `project.md` text, re-parsed with `MarkdownDocument.parse`
|
|
521
|
+
* (K-59; `renderIndex` reads only `frontmatter.type`/`title`/`description`
|
|
522
|
+
* and `path`, never `document`, `CORE/Derive.ts:75-101`, so the synthesized
|
|
523
|
+
* value is faithful). Each per-directory `index.md` is the literal
|
|
524
|
+
* `# <Directory>` — NOT `Derive.renderIndex`, which returns the empty string
|
|
525
|
+
* for an empty concept list with no options (contract Judge notes item 2).
|
|
526
|
+
*
|
|
527
|
+
* @public
|
|
528
|
+
*/
|
|
529
|
+
export declare const files: (options: ScaffoldOptions) => Effect.Effect<ReadonlyArray<ScaffoldFile>, MarkdownParseError | FrontmatterWriteError>;
|
|
530
|
+
//#endregion
|
|
531
|
+
//#region src/render/context.d.ts
|
|
532
|
+
/** One `types[]` entry (M-15). @public */
|
|
533
|
+
export declare const ContextType: Schema.Struct<{
|
|
534
|
+
readonly name: Schema.String;
|
|
535
|
+
readonly description: Schema.NullOr<Schema.String>;
|
|
536
|
+
readonly guidance: Schema.NullOr<Schema.String>;
|
|
537
|
+
}>;
|
|
538
|
+
/** @public */
|
|
539
|
+
export type ContextType = typeof ContextType.Type;
|
|
540
|
+
/** One `tags[]` entry (M-15). @public */
|
|
541
|
+
export declare const ContextTag: Schema.Struct<{
|
|
542
|
+
readonly name: Schema.String;
|
|
543
|
+
readonly description: Schema.NullOr<Schema.String>;
|
|
544
|
+
}>;
|
|
545
|
+
/** @public */
|
|
546
|
+
export type ContextTag = typeof ContextTag.Type;
|
|
547
|
+
/**
|
|
548
|
+
* M-15's envelope: schema 1, snake_case, orientation data only. Distinct
|
|
549
|
+
* from `JsonEnvelope` (`render/json.ts`) — `context` never runs conformance
|
|
550
|
+
* or lint checks, so there is no `diagnostics` array and no `exit_code`
|
|
551
|
+
* field at all.
|
|
552
|
+
*
|
|
553
|
+
* Every field is `Schema.NullOr`, never `Schema.optionalKey`: a consumer
|
|
554
|
+
* (the two hook scripts) reads a fixed key set and gets JSON `null` for an
|
|
555
|
+
* absent value, rather than having to distinguish a missing key from a
|
|
556
|
+
* null one. This is a deliberate difference from `JsonDiagnostic`'s
|
|
557
|
+
* `range`, which is `optionalKey` and omitted when absent
|
|
558
|
+
* (`render/json.ts:14,68`).
|
|
559
|
+
*
|
|
560
|
+
* `profile_requested` (final-review Important 1) is the profile name the
|
|
561
|
+
* config asked for after the K-4 default rule — `resolveProjectConfig`'s
|
|
562
|
+
* own `profileName` — and is `null` only when no config file was found at
|
|
563
|
+
* all. `profile` keeps its original meaning (the resolved profile's name,
|
|
564
|
+
* or `null` when the requested name is unknown or `"none"`). The two
|
|
565
|
+
* differ exactly when a config named an unrecognised profile: `profile`
|
|
566
|
+
* is `null` but `profile_requested` still names what was asked for, so a
|
|
567
|
+
* consumer can tell "no profile configured" apart from "an unknown profile
|
|
568
|
+
* was configured".
|
|
569
|
+
*
|
|
570
|
+
* @public
|
|
571
|
+
*/
|
|
572
|
+
export declare const ContextEnvelope: Schema.Struct<{
|
|
573
|
+
readonly schema: Schema.Literal<1>;
|
|
574
|
+
readonly project_root: Schema.String;
|
|
575
|
+
readonly bundle_root: Schema.String;
|
|
576
|
+
readonly config_path: Schema.NullOr<Schema.String>;
|
|
577
|
+
readonly profile: Schema.NullOr<Schema.String>;
|
|
578
|
+
readonly profile_requested: Schema.NullOr<Schema.String>;
|
|
579
|
+
readonly index_path: Schema.String;
|
|
580
|
+
readonly index_exists: Schema.Boolean;
|
|
581
|
+
readonly actors: Schema.Struct<{
|
|
582
|
+
readonly agent: Schema.NullOr<Schema.String>;
|
|
583
|
+
}>;
|
|
584
|
+
readonly types: Schema.$Array<Schema.Struct<{
|
|
585
|
+
readonly name: Schema.String;
|
|
586
|
+
readonly description: Schema.NullOr<Schema.String>;
|
|
587
|
+
readonly guidance: Schema.NullOr<Schema.String>;
|
|
588
|
+
}>>;
|
|
589
|
+
readonly tags: Schema.$Array<Schema.Struct<{
|
|
590
|
+
readonly name: Schema.String;
|
|
591
|
+
readonly description: Schema.NullOr<Schema.String>;
|
|
592
|
+
}>>;
|
|
593
|
+
}>;
|
|
594
|
+
/** @public */
|
|
595
|
+
export type ContextEnvelope = typeof ContextEnvelope.Type;
|
|
596
|
+
/**
|
|
597
|
+
* Build the envelope from the merged config. `types`/`tags` sort by `name`
|
|
598
|
+
* with plain code-unit comparison, never locale-dependent — the same rule
|
|
599
|
+
* `render/sort.ts`'s K-17 comparator and
|
|
600
|
+
* `packages/profiles/src/SoftwareProject.ts:119`'s own sort use.
|
|
601
|
+
*
|
|
602
|
+
* @public
|
|
603
|
+
*/
|
|
604
|
+
export declare const contextEnvelope: (input: {
|
|
605
|
+
readonly projectRoot: string;
|
|
606
|
+
readonly bundleRoot: string;
|
|
607
|
+
readonly configPath: string | null;
|
|
608
|
+
readonly profile: string | null;
|
|
609
|
+
readonly profileRequested: string | null;
|
|
610
|
+
readonly indexPath: string;
|
|
611
|
+
readonly indexExists: boolean;
|
|
612
|
+
readonly config: OkfitConfig;
|
|
613
|
+
}) => ContextEnvelope;
|
|
614
|
+
/**
|
|
615
|
+
* The `human` format: a short header block, then one line per type and one
|
|
616
|
+
* per tag. Pure; the caller pipes each line through `Console.log`.
|
|
617
|
+
*
|
|
618
|
+
* The `profile:` line reads `profile: (none) (requested NAME, unknown)`
|
|
619
|
+
* when `profile` and `profile_requested` disagree over an actually-unknown
|
|
620
|
+
* profile — never for the `"none"` or no-config cases, where a `null`
|
|
621
|
+
* `profile` is expected, not an error.
|
|
622
|
+
*
|
|
623
|
+
* @public
|
|
624
|
+
*/
|
|
625
|
+
export declare const humanContext: (envelope: ContextEnvelope) => ReadonlyArray<string>;
|
|
626
|
+
//#endregion
|
|
627
|
+
//#region src/render/sort.d.ts
|
|
628
|
+
/** Which producer a diagnostic came from; the JSON envelope's `source` (K-21). @public */
|
|
629
|
+
type DiagnosticSource = "core.conformance" | "core.lint" | "profile";
|
|
630
|
+
/**
|
|
631
|
+
* The one shape both renderers consume. `file` is the bundle-relative posix
|
|
632
|
+
* path core produced, `""` for a bundle-level finding. `range` is core's own
|
|
633
|
+
* zero-based `DiagnosticRange` instance, passed through untouched (K-21).
|
|
634
|
+
* `code` is widened to `string`: core's `DiagnosticCode`
|
|
635
|
+
* (`CORE/Diagnostic.ts:45-46`) and profiles' `ProfileDiagnosticCode`
|
|
636
|
+
* (`PROFILES/Profile.ts:47`) are disjoint closed unions and this carries
|
|
637
|
+
* either.
|
|
638
|
+
*
|
|
639
|
+
* @public
|
|
640
|
+
*/
|
|
641
|
+
interface RenderedDiagnostic {
|
|
642
|
+
readonly source: DiagnosticSource;
|
|
643
|
+
readonly file: string;
|
|
644
|
+
readonly range?: DiagnosticRange;
|
|
645
|
+
readonly code: string;
|
|
646
|
+
readonly severity: DiagnosticSeverity;
|
|
647
|
+
readonly message: string;
|
|
648
|
+
}
|
|
649
|
+
/**
|
|
650
|
+
* Tag core's two arrays and profiles' one, in producer order. Not named
|
|
651
|
+
* `merge`: `OkfitConfig.merge` already owns that word in this codebase.
|
|
652
|
+
*
|
|
653
|
+
* @public
|
|
654
|
+
*/
|
|
655
|
+
export declare const collect: (conformance: ReadonlyArray<Diagnostic>, lint: ReadonlyArray<Diagnostic>, profile: ReadonlyArray<ProfileDiagnostic>) => ReadonlyArray<RenderedDiagnostic>;
|
|
656
|
+
/**
|
|
657
|
+
* K-17: `file` ascending (so `""` — the bundle-level finding — leads), then
|
|
658
|
+
* range-less before ranged within a file, then `range.offset` ascending, then
|
|
659
|
+
* `code`. Plain code-unit comparison, never locale-dependent (the same rule
|
|
660
|
+
* profiles' own `check` sorts by, `PROFILES/SoftwareProject.ts:119`). Stable:
|
|
661
|
+
* implemented with `toSorted`, which is specified as stable.
|
|
662
|
+
*
|
|
663
|
+
* @public
|
|
664
|
+
*/
|
|
665
|
+
export declare const sort: (diagnostics: ReadonlyArray<RenderedDiagnostic>) => ReadonlyArray<RenderedDiagnostic>;
|
|
666
|
+
//#endregion
|
|
667
|
+
//#region src/render/exit.d.ts
|
|
668
|
+
/** @public */
|
|
669
|
+
interface Tally {
|
|
670
|
+
readonly conformanceErrors: number;
|
|
671
|
+
readonly lintErrors: number;
|
|
672
|
+
readonly lintWarnings: number;
|
|
673
|
+
readonly lintInfo: number;
|
|
674
|
+
readonly profileErrors: number;
|
|
675
|
+
}
|
|
676
|
+
/**
|
|
677
|
+
* One pass over the collected diagnostics. `core.conformance` entries are
|
|
678
|
+
* always severity `error` (D-33); the counts are still taken from `severity`
|
|
679
|
+
* so a future non-error conformance code cannot silently change the exit
|
|
680
|
+
* code.
|
|
681
|
+
*
|
|
682
|
+
* @public
|
|
683
|
+
*/
|
|
684
|
+
export declare const tally: (diagnostics: ReadonlyArray<RenderedDiagnostic>) => Tally;
|
|
685
|
+
/**
|
|
686
|
+
* K-7/K-8's two lowest tiers: `2` when any conformance error is present, else
|
|
687
|
+
* `1` when any lint OR profile error is present, else `0`. Warnings and info
|
|
688
|
+
* never move it. `130`, `64` and `3` are set elsewhere — by the runtime's
|
|
689
|
+
* interrupt branch, by the `ShowHelp` remap in `bin.ts`, and by the typed
|
|
690
|
+
* errors' own `[Runtime.errorExitCode]` — so this function returns only
|
|
691
|
+
* `0 | 1 | 2`.
|
|
692
|
+
*
|
|
693
|
+
* @public
|
|
694
|
+
*/
|
|
695
|
+
export declare const forDiagnostics: (diagnostics: ReadonlyArray<RenderedDiagnostic>) => 0 | 1 | 2;
|
|
696
|
+
//#endregion
|
|
697
|
+
//#region src/render/human.d.ts
|
|
698
|
+
/** The counts the summary line reports. @public */
|
|
699
|
+
interface Counts {
|
|
700
|
+
readonly errors: number;
|
|
701
|
+
readonly warnings: number;
|
|
702
|
+
readonly info: number;
|
|
703
|
+
readonly concepts: number;
|
|
704
|
+
}
|
|
705
|
+
/**
|
|
706
|
+
* K-16. With a range:
|
|
707
|
+
* `<file>:<range.line + 1>:<range.character + 1> <severity> <code> <message>`.
|
|
708
|
+
* Without one: `<file> <severity> <code> <message>`. `file: ""` renders as
|
|
709
|
+
* the literal `(bundle)`. Core's range is zero-based (D-32,
|
|
710
|
+
* `CORE/Diagnostic.ts:49-57`); the `+ 1`s here are the only place it becomes
|
|
711
|
+
* one-based. Colour, when `color` is `true`, wraps ONLY the severity word
|
|
712
|
+
* (K-19) — never the code, the path, or the message.
|
|
713
|
+
*
|
|
714
|
+
* @public
|
|
715
|
+
*/
|
|
716
|
+
export declare const line: (diagnostic: RenderedDiagnostic, options?: {
|
|
717
|
+
readonly color?: boolean;
|
|
718
|
+
}) => string;
|
|
719
|
+
/**
|
|
720
|
+
* `sort` then `line` over the whole set: the exact stdout body of
|
|
721
|
+
* `--format human`, one array element per stdout line.
|
|
722
|
+
*
|
|
723
|
+
* @public
|
|
724
|
+
*/
|
|
725
|
+
export declare const human: (diagnostics: ReadonlyArray<RenderedDiagnostic>, options?: {
|
|
726
|
+
readonly color?: boolean;
|
|
727
|
+
}) => ReadonlyArray<string>;
|
|
728
|
+
/**
|
|
729
|
+
* K-20, verbatim and unpluralised —
|
|
730
|
+
* `<E> errors, <W> warnings, <I> info in <N> concepts (<root>)`. `root` is
|
|
731
|
+
* pre-rendered by the caller: relative to cwd when under it, absolute
|
|
732
|
+
* otherwise (K-51).
|
|
733
|
+
*
|
|
734
|
+
* @public
|
|
735
|
+
*/
|
|
736
|
+
export declare const summary: (counts: Counts, root: string) => string;
|
|
737
|
+
//#endregion
|
|
738
|
+
//#region src/render/json.d.ts
|
|
739
|
+
/** One entry of the `diagnostics` array (K-21). @public */
|
|
740
|
+
export declare const JsonDiagnostic: Schema.Struct<{
|
|
741
|
+
readonly source: Schema.Literals<readonly ["core.conformance", "core.lint", "profile"]>;
|
|
742
|
+
readonly file: Schema.String;
|
|
743
|
+
readonly code: Schema.String;
|
|
744
|
+
readonly severity: Schema.Literals<readonly ["error", "warning", "info"]>;
|
|
745
|
+
readonly message: Schema.String;
|
|
746
|
+
readonly range: Schema.optionalKey<typeof DiagnosticRange>;
|
|
747
|
+
}>;
|
|
748
|
+
/** @public */
|
|
749
|
+
export type JsonDiagnostic = typeof JsonDiagnostic.Type;
|
|
750
|
+
/** @public */
|
|
751
|
+
export declare const JsonSummary: Schema.Struct<{
|
|
752
|
+
readonly conformance_errors: Schema.Number;
|
|
753
|
+
readonly lint_errors: Schema.Number;
|
|
754
|
+
readonly lint_warnings: Schema.Number;
|
|
755
|
+
readonly lint_info: Schema.Number;
|
|
756
|
+
readonly profile_errors: Schema.Number;
|
|
757
|
+
readonly concepts: Schema.Number;
|
|
758
|
+
}>;
|
|
759
|
+
/** @public */
|
|
760
|
+
export type JsonSummary = typeof JsonSummary.Type;
|
|
761
|
+
/**
|
|
762
|
+
* K-21's success envelope, snake_case. `exit_code` is `0 | 1 | 2` only: an
|
|
763
|
+
* infrastructure failure never produces this envelope, it produces the
|
|
764
|
+
* `JsonErrorEnvelope` (K-22).
|
|
765
|
+
*
|
|
766
|
+
* @public
|
|
767
|
+
*/
|
|
768
|
+
export declare const JsonEnvelope: Schema.Struct<{
|
|
769
|
+
readonly schema: Schema.Literal<1>;
|
|
770
|
+
readonly okfit_version: Schema.String;
|
|
771
|
+
readonly okf_version: Schema.String;
|
|
772
|
+
readonly root: Schema.String;
|
|
773
|
+
readonly profile: Schema.NullOr<Schema.String>;
|
|
774
|
+
readonly exit_code: Schema.Literals<readonly [0, 1, 2]>;
|
|
775
|
+
readonly summary: Schema.Struct<{
|
|
776
|
+
readonly conformance_errors: Schema.Number;
|
|
777
|
+
readonly lint_errors: Schema.Number;
|
|
778
|
+
readonly lint_warnings: Schema.Number;
|
|
779
|
+
readonly lint_info: Schema.Number;
|
|
780
|
+
readonly profile_errors: Schema.Number;
|
|
781
|
+
readonly concepts: Schema.Number;
|
|
782
|
+
}>;
|
|
783
|
+
readonly diagnostics: Schema.$Array<Schema.Struct<{
|
|
784
|
+
readonly source: Schema.Literals<readonly ["core.conformance", "core.lint", "profile"]>;
|
|
785
|
+
readonly file: Schema.String;
|
|
786
|
+
readonly code: Schema.String;
|
|
787
|
+
readonly severity: Schema.Literals<readonly ["error", "warning", "info"]>;
|
|
788
|
+
readonly message: Schema.String;
|
|
789
|
+
readonly range: Schema.optionalKey<typeof DiagnosticRange>;
|
|
790
|
+
}>>;
|
|
791
|
+
}>;
|
|
792
|
+
/** @public */
|
|
793
|
+
export type JsonEnvelope = typeof JsonEnvelope.Type;
|
|
794
|
+
/** K-22's envelope: the ONLY thing stdout carries under `--format json` on an exit-3 failure. @public */
|
|
795
|
+
export declare const JsonErrorEnvelope: Schema.Struct<{
|
|
796
|
+
readonly schema: Schema.Literal<1>;
|
|
797
|
+
readonly okfit_version: Schema.String;
|
|
798
|
+
readonly exit_code: Schema.Literal<3>;
|
|
799
|
+
readonly error: Schema.Struct<{
|
|
800
|
+
readonly tag: Schema.String;
|
|
801
|
+
readonly message: Schema.String;
|
|
802
|
+
}>;
|
|
803
|
+
}>;
|
|
804
|
+
/** @public */
|
|
805
|
+
export type JsonErrorEnvelope = typeof JsonErrorEnvelope.Type;
|
|
806
|
+
/**
|
|
807
|
+
* Build the success envelope. `diagnostics` is sorted here with the same
|
|
808
|
+
* `sort` the human renderer uses (K-21's "diagnostics are in the K-17
|
|
809
|
+
* order"); `range` passes through as core computed it, zero-based.
|
|
810
|
+
*
|
|
811
|
+
* The value returned is in `Type` form (its `range`s are `DiagnosticRange`
|
|
812
|
+
* instances). What stdout carries is `Schema.encodeSync(JsonEnvelope)` of it,
|
|
813
|
+
* `JSON.stringify`-ed — one document, no trailing text.
|
|
814
|
+
*
|
|
815
|
+
* @public
|
|
816
|
+
*/
|
|
817
|
+
export declare const json: (input: {
|
|
818
|
+
readonly okfitVersion: string;
|
|
819
|
+
readonly okfVersion: string;
|
|
820
|
+
readonly root: string;
|
|
821
|
+
readonly profile: string | null;
|
|
822
|
+
readonly exitCode: 0 | 1 | 2;
|
|
823
|
+
readonly concepts: number;
|
|
824
|
+
readonly diagnostics: ReadonlyArray<RenderedDiagnostic>;
|
|
825
|
+
}) => JsonEnvelope;
|
|
826
|
+
/** K-22. `tag` is the error's `_tag` when it has one, else its constructor name. @public */
|
|
827
|
+
export declare const jsonError: (error: unknown, okfitVersion: string) => JsonErrorEnvelope;
|
|
828
|
+
//#endregion
|
|
829
|
+
//#region src/render/verify.d.ts
|
|
830
|
+
/**
|
|
831
|
+
* V-11's success envelope, schema 1, snake_case — the same convention as
|
|
832
|
+
* `render/json.ts`'s `JsonEnvelope`. Identical in shape for a dry run,
|
|
833
|
+
* which sets `dry_run: true` and still exits 0. There is no content tier,
|
|
834
|
+
* so `exit_code` is the literal `0`; a failure produces K-22's
|
|
835
|
+
* `JsonErrorEnvelope` instead, unchanged.
|
|
836
|
+
*
|
|
837
|
+
* @public
|
|
838
|
+
*/
|
|
839
|
+
export declare const VerifyEnvelope: Schema.Struct<{
|
|
840
|
+
readonly schema: Schema.Literal<1>;
|
|
841
|
+
readonly okfit_version: Schema.String;
|
|
842
|
+
readonly id: Schema.String;
|
|
843
|
+
readonly path: Schema.String;
|
|
844
|
+
readonly verified: Schema.Struct<{
|
|
845
|
+
readonly by: Schema.String;
|
|
846
|
+
readonly at: Schema.String;
|
|
847
|
+
}>;
|
|
848
|
+
readonly dry_run: Schema.Boolean;
|
|
849
|
+
readonly exit_code: Schema.Literal<0>;
|
|
850
|
+
}>;
|
|
851
|
+
/** @public */
|
|
852
|
+
export type VerifyEnvelope = typeof VerifyEnvelope.Type;
|
|
853
|
+
/**
|
|
854
|
+
* `path` is already the display form — `displayRoot(cwd, bundle.root, path)`
|
|
855
|
+
* joined to the bundle-relative `concept.path` — because `LoadedConcept.path`
|
|
856
|
+
* alone would print `decisions/cli-exit-codes.md`, not
|
|
857
|
+
* `okf/decisions/cli-exit-codes.md` (contract §12 note 5).
|
|
858
|
+
*
|
|
859
|
+
* @public
|
|
860
|
+
*/
|
|
861
|
+
export declare const verifyEnvelope: (input: {
|
|
862
|
+
readonly okfitVersion: string;
|
|
863
|
+
readonly id: string;
|
|
864
|
+
readonly path: string;
|
|
865
|
+
readonly by: string;
|
|
866
|
+
readonly at: string;
|
|
867
|
+
readonly dryRun: boolean;
|
|
868
|
+
}) => VerifyEnvelope;
|
|
869
|
+
/** @public */
|
|
870
|
+
interface VerifyLines {
|
|
871
|
+
readonly id: string;
|
|
872
|
+
readonly by: string;
|
|
873
|
+
readonly at: string;
|
|
874
|
+
/** Every prior entry by the SAME actor, in list order (V-2). */
|
|
875
|
+
readonly priorAt: ReadonlyArray<string>;
|
|
876
|
+
readonly dryRun: boolean;
|
|
877
|
+
/** The exact bytes a real run would splice in; printed only when `dryRun`. */
|
|
878
|
+
readonly fragment: string;
|
|
879
|
+
}
|
|
880
|
+
/**
|
|
881
|
+
* V-11's human output: one line per fact. One `already verified` line per
|
|
882
|
+
* prior entry by the same actor, in list order (V-2 says "entries",
|
|
883
|
+
* plural), then the success line. A prior entry by a DIFFERENT actor is
|
|
884
|
+
* not called out: it stays on disk untouched (V-1) and is simply not this
|
|
885
|
+
* line's subject. Under `--dry-run` (I3), a `would write:` header and the
|
|
886
|
+
* exact fragment a real run would splice in follow, so the preview
|
|
887
|
+
* exercises — and shows — the same edit the write path would make.
|
|
5
888
|
*
|
|
6
889
|
* @public
|
|
7
890
|
*/
|
|
8
|
-
declare const
|
|
891
|
+
export declare const humanVerify: (input: VerifyLines) => ReadonlyArray<string>;
|
|
9
892
|
//#endregion
|
|
10
|
-
//#region src/
|
|
893
|
+
//#region src/version.d.ts
|
|
11
894
|
/**
|
|
12
|
-
* The version string reported by `okfit --version
|
|
895
|
+
* The version string reported by `okfit --version`, read from the package's
|
|
896
|
+
* own manifest (K-32) so a release can never desync from the printed
|
|
897
|
+
* version. Consumed by `bin.ts` only.
|
|
13
898
|
*
|
|
14
899
|
* @public
|
|
15
900
|
*/
|
|
16
|
-
declare const CLI_VERSION
|
|
901
|
+
export declare const CLI_VERSION: string;
|
|
17
902
|
//#endregion
|
|
18
|
-
export {
|
|
903
|
+
export type { ConfigReadError, ContextResult, ContextRunOptions, Counts, DiagnosticSource, DiscoveredConfig, RenderedDiagnostic, ResolveProjectConfigInput, ResolvedProjectConfig, RunOptions, RunResult, ScaffoldFile, ScaffoldOptions, Tally, VerifyLines };
|
|
19
904
|
//# sourceMappingURL=index.d.ts.map
|