@okfit/engine 0.10.0 → 0.11.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/errors.js +1 -1
- package/index.d.ts +86 -1
- package/index.js +3 -3
- package/package.json +18 -18
- package/verify/run.js +92 -17
- package/verify/select.js +29 -2
- package/version.js +1 -1
package/errors.js
CHANGED
|
@@ -137,7 +137,7 @@ var VerifySelectionError = class extends Schema.TaggedError()("VerifySelectionEr
|
|
|
137
137
|
}) {
|
|
138
138
|
[Runtime.errorExitCode] = 64;
|
|
139
139
|
get message() {
|
|
140
|
-
if (this.reason === "no-selection") return "verify needs a concept id, --all, or --type <Type>";
|
|
140
|
+
if (this.reason === "no-selection") return "verify needs a concept id, --all, or --type <Type> (run in a terminal to pick interactively)";
|
|
141
141
|
if (this.reason === "id-and-batch") return "verify takes either a concept id or --all/--type, not both";
|
|
142
142
|
if (this.reason === "status-conflict") return "verify takes --stable or --draft, not both";
|
|
143
143
|
if (this.reason === "status-and-batch") return "--stable and --draft need a concept id; batch mode never changes status";
|
package/index.d.ts
CHANGED
|
@@ -1577,6 +1577,30 @@ interface AttestableSelection {
|
|
|
1577
1577
|
* @public
|
|
1578
1578
|
*/
|
|
1579
1579
|
export declare const selectAttestable: (bundle: LoadedBundle, types: ReadonlySet<string>, actor: string) => AttestableSelection;
|
|
1580
|
+
/**
|
|
1581
|
+
* One row of the interactive verify picker: a `require_verified` concept the
|
|
1582
|
+
* actor has not attested yet.
|
|
1583
|
+
*
|
|
1584
|
+
* @public
|
|
1585
|
+
*/
|
|
1586
|
+
interface PickerCandidate {
|
|
1587
|
+
readonly id: string;
|
|
1588
|
+
readonly type: string;
|
|
1589
|
+
/** `"stable"` when the concept carries no `status`. */
|
|
1590
|
+
readonly status: "draft" | "stable";
|
|
1591
|
+
readonly title: string | null;
|
|
1592
|
+
readonly description: string | null;
|
|
1593
|
+
/** How many `verified` entries by actors other than the current one. */
|
|
1594
|
+
readonly otherAttestations: number;
|
|
1595
|
+
}
|
|
1596
|
+
/**
|
|
1597
|
+
* Every concept whose type sets `require_verified` that `actor` has not
|
|
1598
|
+
* attested: drafts included, deprecated concepts and the actor's own
|
|
1599
|
+
* attestations excluded. Sorted by type, then id; grouping is the caller's.
|
|
1600
|
+
*
|
|
1601
|
+
* @public
|
|
1602
|
+
*/
|
|
1603
|
+
export declare const selectPickerCandidates: (bundle: LoadedBundle, config: OkfitConfig, actor: string) => ReadonlyArray<PickerCandidate>;
|
|
1580
1604
|
/**
|
|
1581
1605
|
* The batch type-resolution rule shared by `runVerifyBatch` and any future
|
|
1582
1606
|
* interactive picker: explicit `types` must each be declared in
|
|
@@ -2035,6 +2059,67 @@ export declare const runVerifyBatch: (options: VerifyBatchOptions) => Effect.Eff
|
|
|
2035
2059
|
readonly reason: VerifyBatchSkipReason;
|
|
2036
2060
|
}[];
|
|
2037
2061
|
}, import("effect/PlatformError").PlatformError | VerifySelectionError | VerifyUnsupportedFrontmatterError | import("@effected/yaml").YamlParseError | import("@okfit/core").BundleLoadError | import("@okfit/profiles").GeneratedByError, FileSystem.FileSystem | import("@effected/git").Git | Path.Path>;
|
|
2062
|
+
/**
|
|
2063
|
+
* Issue #214: options for {@link runVerifyIds}.
|
|
2064
|
+
*
|
|
2065
|
+
* @public
|
|
2066
|
+
*/
|
|
2067
|
+
interface VerifyIdsOptions {
|
|
2068
|
+
readonly bundleRoot: string;
|
|
2069
|
+
readonly projectRoot: string;
|
|
2070
|
+
readonly config: OkfitConfig;
|
|
2071
|
+
readonly at: DateTime.Utc;
|
|
2072
|
+
readonly dryRun: boolean;
|
|
2073
|
+
/** Concept ids, resolved as `runVerify` resolves one (tolerant: leading slash, trailing `.md`). */
|
|
2074
|
+
readonly ids: ReadonlyArray<string>;
|
|
2075
|
+
/** Also set `status: stable` on every selected concept whose status is `draft`. Default `false`. */
|
|
2076
|
+
readonly promote?: boolean;
|
|
2077
|
+
}
|
|
2078
|
+
/**
|
|
2079
|
+
* Issue #214. Attests an explicit list of concept ids in one all-or-nothing
|
|
2080
|
+
* batch. Every id is resolved exactly as {@link runVerify} resolves it, and
|
|
2081
|
+
* every concept is located and spliced BEFORE any file is written, so one
|
|
2082
|
+
* unknown id, reserved file or unsupported `verified`/`status` shape fails the
|
|
2083
|
+
* whole call with the tree untouched. An explicit pick is never second-guessed:
|
|
2084
|
+
* drafts, deprecated and already-attested concepts are all attested, and
|
|
2085
|
+
* `skipped` is always empty. Duplicate ids (after normalisation) are written
|
|
2086
|
+
* once. With `promote`, a draft's `status` becomes `stable` in the same write.
|
|
2087
|
+
*
|
|
2088
|
+
* @public
|
|
2089
|
+
*/
|
|
2090
|
+
export declare const runVerifyIds: (options: VerifyIdsOptions) => Effect.Effect<{
|
|
2091
|
+
bundleRoot: string;
|
|
2092
|
+
by: Actor;
|
|
2093
|
+
at: string;
|
|
2094
|
+
dryRun: boolean;
|
|
2095
|
+
verified: {
|
|
2096
|
+
id: string;
|
|
2097
|
+
conceptPath: string;
|
|
2098
|
+
fragment: string;
|
|
2099
|
+
}[];
|
|
2100
|
+
skipped: never[];
|
|
2101
|
+
}, import("effect/PlatformError").PlatformError | VerifyConceptNotFoundError | VerifyUnsupportedFrontmatterError | import("@effected/yaml").YamlParseError | import("@okfit/core").BundleLoadError | import("@okfit/profiles").GeneratedByError, FileSystem.FileSystem | import("@effected/git").Git | Path.Path>;
|
|
2102
|
+
/**
|
|
2103
|
+
* Options for {@link loadPickerCandidates}.
|
|
2104
|
+
*
|
|
2105
|
+
* @public
|
|
2106
|
+
*/
|
|
2107
|
+
interface PickerCandidatesOptions {
|
|
2108
|
+
readonly bundleRoot: string;
|
|
2109
|
+
readonly projectRoot: string;
|
|
2110
|
+
readonly config: OkfitConfig;
|
|
2111
|
+
}
|
|
2112
|
+
/**
|
|
2113
|
+
* The interactive verify picker's starting point: loads the bundle, resolves
|
|
2114
|
+
* the human actor from git exactly as {@link runVerify} does, and selects the
|
|
2115
|
+
* rows that actor may still attest. Reads only; nothing is written.
|
|
2116
|
+
*
|
|
2117
|
+
* @public
|
|
2118
|
+
*/
|
|
2119
|
+
export declare const loadPickerCandidates: (options: PickerCandidatesOptions) => Effect.Effect<{
|
|
2120
|
+
by: Actor;
|
|
2121
|
+
candidates: readonly PickerCandidate[];
|
|
2122
|
+
}, import("@okfit/core").BundleLoadError | import("@okfit/profiles").GeneratedByError, FileSystem.FileSystem | import("@effected/git").Git | Path.Path>;
|
|
2038
2123
|
//#endregion
|
|
2039
2124
|
//#region src/version.d.ts
|
|
2040
2125
|
/**
|
|
@@ -2051,5 +2136,5 @@ export declare const runVerifyBatch: (options: VerifyBatchOptions) => Effect.Eff
|
|
|
2051
2136
|
*/
|
|
2052
2137
|
export declare const ENGINE_VERSION: string;
|
|
2053
2138
|
//#endregion
|
|
2054
|
-
export type { AttestableSelection, BundleSessionOptions, BundleSessionServices, BundleSessionShape, ConceptFilter, ConceptLink, ConceptNeighbor, ContextResult, ContextRunOptions, DiagnosticSource, DiscoveredConfig, Distribution, DocumentInput, ExternalReferencesShape, GraphRunOptions, GraphRunResult, OverlayDocument, OverlayDocumentsShape, RenderedDiagnostic, ResolveProjectConfigInput, ResolvedProjectConfig, RevalidateError, RevalidateOptions, RevalidateResult, RevalidateTier, RunOptions, RunResult, ScaffoldFile, ScaffoldOptions, StaleRunOptions, StaleRunResult, SyncMode, SyncModeResult, SyncOptions, SyncResult, Tally, VerifyBatchOptions, VerifyBatchResult, VerifyBatchSkipReason, VerifyOptions, VerifyResult, WatchedFilesOutcome };
|
|
2139
|
+
export type { AttestableSelection, BundleSessionOptions, BundleSessionServices, BundleSessionShape, ConceptFilter, ConceptLink, ConceptNeighbor, ContextResult, ContextRunOptions, DiagnosticSource, DiscoveredConfig, Distribution, DocumentInput, ExternalReferencesShape, GraphRunOptions, GraphRunResult, OverlayDocument, OverlayDocumentsShape, PickerCandidate, PickerCandidatesOptions, RenderedDiagnostic, ResolveProjectConfigInput, ResolvedProjectConfig, RevalidateError, RevalidateOptions, RevalidateResult, RevalidateTier, RunOptions, RunResult, ScaffoldFile, ScaffoldOptions, StaleRunOptions, StaleRunResult, SyncMode, SyncModeResult, SyncOptions, SyncResult, Tally, VerifyBatchOptions, VerifyBatchResult, VerifyBatchSkipReason, VerifyIdsOptions, VerifyOptions, VerifyResult, WatchedFilesOutcome };
|
|
2055
2140
|
//# sourceMappingURL=index.d.ts.map
|
package/index.js
CHANGED
|
@@ -28,7 +28,7 @@ import { conceptFor } from "./session/concept.js";
|
|
|
28
28
|
import { withFallbackRange } from "./session/range.js";
|
|
29
29
|
import { BundleSession } from "./session/BundleSession.js";
|
|
30
30
|
import { runStale } from "./stale/run.js";
|
|
31
|
-
import { resolveBatchTypes, selectAttestable } from "./verify/select.js";
|
|
32
|
-
import { runVerify, runVerifyBatch } from "./verify/run.js";
|
|
31
|
+
import { resolveBatchTypes, selectAttestable, selectPickerCandidates } from "./verify/select.js";
|
|
32
|
+
import { loadPickerCandidates, runVerify, runVerifyBatch, runVerifyIds } from "./verify/run.js";
|
|
33
33
|
|
|
34
|
-
export { BundleSession, CONFIG_RELATIVE_PATH, ConceptQuery, ConceptSummary, ConfigMalformedError, ConfigPathNotFoundError, ContextEnvelope, ContextField, ContextFieldValue, ContextTag, ContextType, DEFAULT_PROFILE_NAME, DistributionField, DocumentPathError, ENGINE_VERSION, ExternalReferences, FrontmatterEdits, GraphEdgeEnvelope, GraphEnvelope, GraphNodeEnvelope, GraphSummary, InitOverwriteError, JsonDiagnostic, JsonEnvelope, JsonErrorEnvelope, JsonSummary, Now, OkfitPlatform, OverlayDocuments, QueryConceptNotFoundError, QueryGetEnvelope, QueryLink, QueryListEnvelope, QueryNeighbor, QueryNeighborsEnvelope, QuerySelectionError, QueryUnknownVocabularyError, ReferenceCheck, ReferenceState, SkipReason, StaleEnvelope, StaleItem, StaleSummary, SyncEnvelope, SyncModeEnvelope, SyncStagedLogError, UnsupportedFrontmatterError, VerifyBatchEnvelope, VerifyConceptNotFoundError, VerifyEnvelope, VerifySelectionError, VerifyUnsupportedFrontmatterError, buildConfigLayer, collect, conceptFor, configValue, contextEnvelope, files, forDiagnostics, graphEnvelope, json, jsonError, layerOverlayFileSystem, makeOverlayFileSystem, provideConfig, provideDocuments, queryGetEnvelope, queryListEnvelope, queryNeighborsEnvelope, resolveBatchTypes, resolveBundleRoot, resolveDocumentPath, resolveProjectConfig, resolveProjectRoot, run, runContext, runGraph, runStale, runSync, runVerify, runVerifyBatch, selectAttestable, sort, staleEnvelope, syncEnvelope, tally, targetPaths, toConceptSummary, verifyBatchEnvelope, verifyEnvelope, withFallbackRange };
|
|
34
|
+
export { BundleSession, CONFIG_RELATIVE_PATH, ConceptQuery, ConceptSummary, ConfigMalformedError, ConfigPathNotFoundError, ContextEnvelope, ContextField, ContextFieldValue, ContextTag, ContextType, DEFAULT_PROFILE_NAME, DistributionField, DocumentPathError, ENGINE_VERSION, ExternalReferences, FrontmatterEdits, GraphEdgeEnvelope, GraphEnvelope, GraphNodeEnvelope, GraphSummary, InitOverwriteError, JsonDiagnostic, JsonEnvelope, JsonErrorEnvelope, JsonSummary, Now, OkfitPlatform, OverlayDocuments, QueryConceptNotFoundError, QueryGetEnvelope, QueryLink, QueryListEnvelope, QueryNeighbor, QueryNeighborsEnvelope, QuerySelectionError, QueryUnknownVocabularyError, ReferenceCheck, ReferenceState, SkipReason, StaleEnvelope, StaleItem, StaleSummary, SyncEnvelope, SyncModeEnvelope, SyncStagedLogError, UnsupportedFrontmatterError, VerifyBatchEnvelope, VerifyConceptNotFoundError, VerifyEnvelope, VerifySelectionError, VerifyUnsupportedFrontmatterError, buildConfigLayer, collect, conceptFor, configValue, contextEnvelope, files, forDiagnostics, graphEnvelope, json, jsonError, layerOverlayFileSystem, loadPickerCandidates, makeOverlayFileSystem, provideConfig, provideDocuments, queryGetEnvelope, queryListEnvelope, queryNeighborsEnvelope, resolveBatchTypes, resolveBundleRoot, resolveDocumentPath, resolveProjectConfig, resolveProjectRoot, run, runContext, runGraph, runStale, runSync, runVerify, runVerifyBatch, runVerifyIds, selectAttestable, selectPickerCandidates, sort, staleEnvelope, syncEnvelope, tally, targetPaths, toConceptSummary, verifyBatchEnvelope, verifyEnvelope, withFallbackRange };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@okfit/engine",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "The okfit engine: platform layer, config discovery, and the validate, verify, sync, init and context programs shared by the okfit CLI and MCP server.",
|
|
6
6
|
"keywords": [
|
|
@@ -34,23 +34,23 @@
|
|
|
34
34
|
"./package.json": "./package.json"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@effect/platform-node": "4.0.0
|
|
38
|
-
"@effected/app": "^0.
|
|
39
|
-
"@effected/config-file": "^0.
|
|
40
|
-
"@effected/engine": "^0.
|
|
41
|
-
"@effected/git": "^0.
|
|
42
|
-
"@effected/glob": "^0.
|
|
43
|
-
"@effected/jsonc": "^0.
|
|
44
|
-
"@effected/markdown": "^0.
|
|
45
|
-
"@effected/schemastore": "^0.
|
|
46
|
-
"@effected/store": "^0.
|
|
47
|
-
"@effected/toml": "^0.
|
|
48
|
-
"@effected/walker": "^0.
|
|
49
|
-
"@effected/xdg": "^0.
|
|
50
|
-
"@effected/yaml": "^0.
|
|
51
|
-
"@okfit/core": "0.8.
|
|
52
|
-
"@okfit/profiles": "0.8.
|
|
53
|
-
"effect": "4.0.0
|
|
37
|
+
"@effect/platform-node": "^4.0.0",
|
|
38
|
+
"@effected/app": "^0.20.0",
|
|
39
|
+
"@effected/config-file": "^0.14.0",
|
|
40
|
+
"@effected/engine": "^0.3.0",
|
|
41
|
+
"@effected/git": "^0.20.0",
|
|
42
|
+
"@effected/glob": "^0.10.0",
|
|
43
|
+
"@effected/jsonc": "^0.15.0",
|
|
44
|
+
"@effected/markdown": "^0.15.0",
|
|
45
|
+
"@effected/schemastore": "^0.18.0",
|
|
46
|
+
"@effected/store": "^0.12.0",
|
|
47
|
+
"@effected/toml": "^0.11.0",
|
|
48
|
+
"@effected/walker": "^0.15.0",
|
|
49
|
+
"@effected/xdg": "^0.9.0",
|
|
50
|
+
"@effected/yaml": "^0.19.0",
|
|
51
|
+
"@okfit/core": "0.8.4",
|
|
52
|
+
"@okfit/profiles": "0.8.3",
|
|
53
|
+
"effect": "^4.0.0"
|
|
54
54
|
},
|
|
55
55
|
"engines": {
|
|
56
56
|
"node": ">=24.11.0"
|
package/verify/run.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { VerifyConceptNotFoundError, VerifyUnsupportedFrontmatterError } from "../errors.js";
|
|
2
2
|
import { documentNewline, locate, locateTopLevelScalar, stripBom } from "./locate.js";
|
|
3
3
|
import { mergeSameOffset, splice, spliceTopLevelScalar } from "./splice.js";
|
|
4
|
-
import { resolveBatchTypes, selectAttestable } from "./select.js";
|
|
4
|
+
import { resolveBatchTypes, selectAttestable, selectPickerCandidates } from "./select.js";
|
|
5
5
|
import { Bundle, ConceptId, Timestamp } from "@okfit/core";
|
|
6
6
|
import { Effect, FileSystem, Option, Path, Schema } from "effect";
|
|
7
7
|
import { Derivation } from "@okfit/profiles";
|
|
@@ -71,22 +71,11 @@ const writeVerified = Effect.fn("okfit/verify/writeVerified")(function* (absolut
|
|
|
71
71
|
yield* fs.chmod(tempPath, original.mode);
|
|
72
72
|
yield* fs.rename(tempPath, target).pipe(Effect.onError(() => fs.remove(tempPath, { force: true }).pipe(Effect.ignore)));
|
|
73
73
|
});
|
|
74
|
-
/**
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
* frontmatter and writes it back atomically.
|
|
78
|
-
*
|
|
79
|
-
* Nothing here reads `stale_after` or a type's `require_verified`; `status`
|
|
80
|
-
* is read only to skip a no-op edit under `options.status` (#185). `verify`
|
|
81
|
-
* is mechanical, not config-aware (V-4, V-5).
|
|
82
|
-
*
|
|
83
|
-
* @internal
|
|
84
|
-
*/
|
|
85
|
-
const runVerify = Effect.fn("okfit/verify/runVerify")(function* (options) {
|
|
86
|
-
const bundle = yield* Bundle.load({ root: options.bundleRoot });
|
|
87
|
-
const normalized = ConceptId.normalize(options.id);
|
|
74
|
+
/** Steps 7a-7d of runVerify, shared with `runVerifyIds`: tolerant id, reserved file, located concept. */
|
|
75
|
+
const resolveConcept = (bundle, rawId) => Effect.gen(function* () {
|
|
76
|
+
const normalized = ConceptId.normalize(rawId);
|
|
88
77
|
if (Option.isNone(normalized)) return yield* new VerifyConceptNotFoundError({
|
|
89
|
-
id:
|
|
78
|
+
id: rawId,
|
|
90
79
|
root: bundle.root,
|
|
91
80
|
reason: "not-a-concept"
|
|
92
81
|
});
|
|
@@ -109,6 +98,25 @@ const runVerify = Effect.fn("okfit/verify/runVerify")(function* (options) {
|
|
|
109
98
|
}
|
|
110
99
|
});
|
|
111
100
|
}
|
|
101
|
+
return {
|
|
102
|
+
id,
|
|
103
|
+
concept
|
|
104
|
+
};
|
|
105
|
+
});
|
|
106
|
+
/**
|
|
107
|
+
* Contract §2.3 steps 6–15. Loads the bundle, resolves the id, resolves the
|
|
108
|
+
* human actor from git, splices exactly one entry into the concept's
|
|
109
|
+
* frontmatter and writes it back atomically.
|
|
110
|
+
*
|
|
111
|
+
* Nothing here reads `stale_after` or a type's `require_verified`; `status`
|
|
112
|
+
* is read only to skip a no-op edit under `options.status` (#185). `verify`
|
|
113
|
+
* is mechanical, not config-aware (V-4, V-5).
|
|
114
|
+
*
|
|
115
|
+
* @internal
|
|
116
|
+
*/
|
|
117
|
+
const runVerify = Effect.fn("okfit/verify/runVerify")(function* (options) {
|
|
118
|
+
const bundle = yield* Bundle.load({ root: options.bundleRoot });
|
|
119
|
+
const { id, concept } = yield* resolveConcept(bundle, options.id);
|
|
112
120
|
const actor = yield* Derivation.generatedBy({
|
|
113
121
|
writer: "human",
|
|
114
122
|
cwd: options.projectRoot,
|
|
@@ -173,6 +181,73 @@ const runVerifyBatch = Effect.fn("okfit/verify/runVerifyBatch")(function* (optio
|
|
|
173
181
|
skipped: selection.skipped
|
|
174
182
|
};
|
|
175
183
|
});
|
|
184
|
+
/**
|
|
185
|
+
* Issue #214. Attests an explicit list of concept ids in one all-or-nothing
|
|
186
|
+
* batch. Every id is resolved exactly as {@link runVerify} resolves it, and
|
|
187
|
+
* every concept is located and spliced BEFORE any file is written, so one
|
|
188
|
+
* unknown id, reserved file or unsupported `verified`/`status` shape fails the
|
|
189
|
+
* whole call with the tree untouched. An explicit pick is never second-guessed:
|
|
190
|
+
* drafts, deprecated and already-attested concepts are all attested, and
|
|
191
|
+
* `skipped` is always empty. Duplicate ids (after normalisation) are written
|
|
192
|
+
* once. With `promote`, a draft's `status` becomes `stable` in the same write.
|
|
193
|
+
*
|
|
194
|
+
* @public
|
|
195
|
+
*/
|
|
196
|
+
const runVerifyIds = Effect.fn("okfit/verify/runVerifyIds")(function* (options) {
|
|
197
|
+
const bundle = yield* Bundle.load({ root: options.bundleRoot });
|
|
198
|
+
const actor = yield* Derivation.generatedBy({
|
|
199
|
+
writer: "human",
|
|
200
|
+
cwd: options.projectRoot,
|
|
201
|
+
config: options.config
|
|
202
|
+
});
|
|
203
|
+
const at = Schema.encodeSync(Timestamp)(options.at);
|
|
204
|
+
const concepts = /* @__PURE__ */ new Map();
|
|
205
|
+
for (const rawId of options.ids) {
|
|
206
|
+
const { id, concept } = yield* resolveConcept(bundle, rawId);
|
|
207
|
+
concepts.set(id, concept);
|
|
208
|
+
}
|
|
209
|
+
const prepared = [];
|
|
210
|
+
for (const [id, concept] of concepts) {
|
|
211
|
+
const status = options.promote === true && concept.frontmatter.status === "draft" ? "stable" : void 0;
|
|
212
|
+
prepared.push({
|
|
213
|
+
id,
|
|
214
|
+
conceptPath: concept.path,
|
|
215
|
+
...yield* prepareVerify(bundle, concept, actor, at, status)
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
if (!options.dryRun) for (const entry of prepared) yield* writeVerified(entry.absolutePath, entry.finalText);
|
|
219
|
+
return {
|
|
220
|
+
bundleRoot: bundle.root,
|
|
221
|
+
by: actor,
|
|
222
|
+
at,
|
|
223
|
+
dryRun: options.dryRun,
|
|
224
|
+
verified: prepared.map(({ id, conceptPath, fragment }) => ({
|
|
225
|
+
id,
|
|
226
|
+
conceptPath,
|
|
227
|
+
fragment
|
|
228
|
+
})),
|
|
229
|
+
skipped: []
|
|
230
|
+
};
|
|
231
|
+
});
|
|
232
|
+
/**
|
|
233
|
+
* The interactive verify picker's starting point: loads the bundle, resolves
|
|
234
|
+
* the human actor from git exactly as {@link runVerify} does, and selects the
|
|
235
|
+
* rows that actor may still attest. Reads only; nothing is written.
|
|
236
|
+
*
|
|
237
|
+
* @public
|
|
238
|
+
*/
|
|
239
|
+
const loadPickerCandidates = Effect.fn("okfit/verify/loadPickerCandidates")(function* (options) {
|
|
240
|
+
const bundle = yield* Bundle.load({ root: options.bundleRoot });
|
|
241
|
+
const by = yield* Derivation.generatedBy({
|
|
242
|
+
writer: "human",
|
|
243
|
+
cwd: options.projectRoot,
|
|
244
|
+
config: options.config
|
|
245
|
+
});
|
|
246
|
+
return {
|
|
247
|
+
by,
|
|
248
|
+
candidates: selectPickerCandidates(bundle, options.config, by)
|
|
249
|
+
};
|
|
250
|
+
});
|
|
176
251
|
|
|
177
252
|
//#endregion
|
|
178
|
-
export { runVerify, runVerifyBatch };
|
|
253
|
+
export { loadPickerCandidates, runVerify, runVerifyBatch, runVerifyIds };
|
package/verify/select.js
CHANGED
|
@@ -36,6 +36,33 @@ const selectAttestable = (bundle, types, actor) => {
|
|
|
36
36
|
skipped
|
|
37
37
|
};
|
|
38
38
|
};
|
|
39
|
+
const requireVerifiedTypes = (config) => new Set(Object.entries(config.types ?? {}).flatMap(([name, spec]) => spec.require_verified === true ? [name] : []));
|
|
40
|
+
/**
|
|
41
|
+
* Every concept whose type sets `require_verified` that `actor` has not
|
|
42
|
+
* attested: drafts included, deprecated concepts and the actor's own
|
|
43
|
+
* attestations excluded. Sorted by type, then id; grouping is the caller's.
|
|
44
|
+
*
|
|
45
|
+
* @public
|
|
46
|
+
*/
|
|
47
|
+
const selectPickerCandidates = (bundle, config, actor) => {
|
|
48
|
+
const types = requireVerifiedTypes(config);
|
|
49
|
+
const rows = [];
|
|
50
|
+
for (const [id, concept] of bundle.concepts) {
|
|
51
|
+
const { type, status, title, description } = concept.frontmatter;
|
|
52
|
+
if (!types.has(type) || status === "deprecated") continue;
|
|
53
|
+
const verified = concept.frontmatter.verified ?? [];
|
|
54
|
+
if (verified.some((entry) => entry.by === actor)) continue;
|
|
55
|
+
rows.push({
|
|
56
|
+
id,
|
|
57
|
+
type,
|
|
58
|
+
status: status === "draft" ? "draft" : "stable",
|
|
59
|
+
title: title ?? null,
|
|
60
|
+
description: description ?? null,
|
|
61
|
+
otherAttestations: verified.length
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
return rows.toSorted((a, b) => a.type < b.type ? -1 : a.type > b.type ? 1 : a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
|
|
65
|
+
};
|
|
39
66
|
/**
|
|
40
67
|
* The batch type-resolution rule shared by `runVerifyBatch` and any future
|
|
41
68
|
* interactive picker: explicit `types` must each be declared in
|
|
@@ -47,7 +74,7 @@ const selectAttestable = (bundle, types, actor) => {
|
|
|
47
74
|
*/
|
|
48
75
|
const resolveBatchTypes = (config, types) => {
|
|
49
76
|
const declared = config.types ?? {};
|
|
50
|
-
if (types.length === 0) return Effect.succeed(
|
|
77
|
+
if (types.length === 0) return Effect.succeed(requireVerifiedTypes(config));
|
|
51
78
|
for (const type of types) if (!Object.hasOwn(declared, type)) return Effect.fail(new VerifySelectionError({
|
|
52
79
|
reason: "unknown-type",
|
|
53
80
|
detail: type
|
|
@@ -56,4 +83,4 @@ const resolveBatchTypes = (config, types) => {
|
|
|
56
83
|
};
|
|
57
84
|
|
|
58
85
|
//#endregion
|
|
59
|
-
export { resolveBatchTypes, selectAttestable };
|
|
86
|
+
export { resolveBatchTypes, selectAttestable, selectPickerCandidates };
|