@okfit/engine 0.4.1 → 0.6.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/index.d.ts +11 -1
- package/index.js +2 -2
- package/init/scaffold.js +18 -2
- package/package.json +7 -6
- package/validate/resources.js +73 -0
- package/validate/run.js +7 -1
package/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { AppDirs, Xdg } from "@effected/xdg";
|
|
|
4
4
|
import { ConfigReadError } from "@effected/config-file";
|
|
5
5
|
import { GeneratedAtError, GitHistory, GitHistoryError, Layout, Profile, ProfileDiagnostic } from "@okfit/profiles";
|
|
6
6
|
import { FrontmatterWriteError, MarkdownParseError } from "@effected/markdown";
|
|
7
|
+
import { HostedSchema } from "@effected/schemastore";
|
|
7
8
|
import * as NodeServices from "@effect/platform-node/NodeServices";
|
|
8
9
|
import { Git, GitCommandError, UnknownRefError } from "@effected/git";
|
|
9
10
|
//#region src/config/anchor.d.ts
|
|
@@ -353,8 +354,17 @@ export declare const runGraph: (options: GraphRunOptions) => Effect.Effect<Graph
|
|
|
353
354
|
//#region src/init/scaffold.d.ts
|
|
354
355
|
/** `.config/okfit.toml`, relative to the project root (C-10). @public */
|
|
355
356
|
export declare const CONFIG_RELATIVE_PATH = ".config/okfit.toml";
|
|
357
|
+
/**
|
|
358
|
+
* Where the published `config` JSON Schema document lives and which version
|
|
359
|
+
* is current — the one identity `schemastore.config.ts` and `okfit init`'s
|
|
360
|
+
* `#:schema` directive both derive from, so the URL a fresh config points at
|
|
361
|
+
* and the one the generated document declares can never disagree (C-18).
|
|
362
|
+
*
|
|
363
|
+
* @public
|
|
364
|
+
*/
|
|
365
|
+
export declare const okfitConfigSchemaHost: HostedSchema;
|
|
356
366
|
/** C-22's directive, plus the blank line Tombi requires. @public */
|
|
357
|
-
export declare const SCHEMA_DIRECTIVE
|
|
367
|
+
export declare const SCHEMA_DIRECTIVE: string;
|
|
358
368
|
/** @public */
|
|
359
369
|
interface ScaffoldOptions {
|
|
360
370
|
/** Absolute. */
|
package/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { buildConfigLayer, provideConfig } from "./config/layer.js";
|
|
|
4
4
|
import { DEFAULT_PROFILE_NAME, resolveProjectConfig } from "./config/resolve.js";
|
|
5
5
|
import { runContext } from "./context/run.js";
|
|
6
6
|
import { runGraph } from "./graph/run.js";
|
|
7
|
-
import { CONFIG_RELATIVE_PATH, SCHEMA_DIRECTIVE, configValue, files, targetPaths } from "./init/scaffold.js";
|
|
7
|
+
import { CONFIG_RELATIVE_PATH, SCHEMA_DIRECTIVE, configValue, files, okfitConfigSchemaHost, targetPaths } from "./init/scaffold.js";
|
|
8
8
|
import { OkfitPlatform } from "./platform.js";
|
|
9
9
|
import { ContextEnvelope, ContextField, ContextFieldValue, ContextTag, ContextType, contextEnvelope } from "./render/context.js";
|
|
10
10
|
import { forDiagnostics, tally } from "./render/exit.js";
|
|
@@ -19,4 +19,4 @@ import { runStale } from "./stale/run.js";
|
|
|
19
19
|
import { Now, run } from "./validate/run.js";
|
|
20
20
|
import { runVerify } from "./verify/run.js";
|
|
21
21
|
|
|
22
|
-
export { CONFIG_RELATIVE_PATH, ConfigMalformedError, ConfigPathNotFoundError, ContextEnvelope, ContextField, ContextFieldValue, ContextTag, ContextType, DEFAULT_PROFILE_NAME, GraphEdgeEnvelope, GraphEnvelope, GraphNodeEnvelope, GraphSummary, InitOverwriteError, JsonDiagnostic, JsonEnvelope, JsonErrorEnvelope, JsonSummary, Now, OkfitPlatform, SCHEMA_DIRECTIVE, SkipReason, StaleEnvelope, StaleItem, StaleSummary, SyncEnvelope, SyncModeEnvelope, VerifyConceptNotFoundError, VerifyEnvelope, VerifyUnsupportedFrontmatterError, buildConfigLayer, collect, configValue, contextEnvelope, files, forDiagnostics, graphEnvelope, json, jsonError, provideConfig, resolveBundleRoot, resolveProjectConfig, resolveProjectRoot, run, runContext, runGraph, runStale, runSync, runVerify, sort, staleEnvelope, syncEnvelope, tally, targetPaths, verifyEnvelope };
|
|
22
|
+
export { CONFIG_RELATIVE_PATH, ConfigMalformedError, ConfigPathNotFoundError, ContextEnvelope, ContextField, ContextFieldValue, ContextTag, ContextType, DEFAULT_PROFILE_NAME, GraphEdgeEnvelope, GraphEnvelope, GraphNodeEnvelope, GraphSummary, InitOverwriteError, JsonDiagnostic, JsonEnvelope, JsonErrorEnvelope, JsonSummary, Now, OkfitPlatform, SCHEMA_DIRECTIVE, SkipReason, StaleEnvelope, StaleItem, StaleSummary, SyncEnvelope, SyncModeEnvelope, VerifyConceptNotFoundError, VerifyEnvelope, VerifyUnsupportedFrontmatterError, buildConfigLayer, collect, configValue, contextEnvelope, files, forDiagnostics, graphEnvelope, json, jsonError, okfitConfigSchemaHost, provideConfig, resolveBundleRoot, resolveProjectConfig, resolveProjectRoot, run, runContext, runGraph, runStale, runSync, runVerify, sort, staleEnvelope, syncEnvelope, tally, targetPaths, verifyEnvelope };
|
package/init/scaffold.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Concept, ConceptId, Derive, LoadedConcept, OKF_SPEC_VERSION } from "@okfit/core";
|
|
2
2
|
import { Effect, Option, Schema } from "effect";
|
|
3
3
|
import { MarkdownDocument, MarkdownFrontmatter, MarkdownParseOptions, YamlFrontmatter } from "@effected/markdown";
|
|
4
|
+
import { HostedSchema } from "@effected/schemastore";
|
|
4
5
|
|
|
5
6
|
//#region src/init/scaffold.ts
|
|
6
7
|
/** `.config/okfit.toml`, relative to the project root (C-10). @public */
|
|
@@ -21,8 +22,23 @@ const PROJECT_CONFIG_NAMES = [
|
|
|
21
22
|
"okfit.toml",
|
|
22
23
|
".config/okfit.toml"
|
|
23
24
|
];
|
|
25
|
+
/**
|
|
26
|
+
* Where the published `config` JSON Schema document lives and which version
|
|
27
|
+
* is current — the one identity `schemastore.config.ts` and `okfit init`'s
|
|
28
|
+
* `#:schema` directive both derive from, so the URL a fresh config points at
|
|
29
|
+
* and the one the generated document declares can never disagree (C-18).
|
|
30
|
+
*
|
|
31
|
+
* @public
|
|
32
|
+
*/
|
|
33
|
+
const okfitConfigSchemaHost = HostedSchema.github({
|
|
34
|
+
repo: "spencerbeggs/okfit",
|
|
35
|
+
path: "schemas",
|
|
36
|
+
name: "config",
|
|
37
|
+
versions: ["1.0"],
|
|
38
|
+
appendVersion: false
|
|
39
|
+
});
|
|
24
40
|
/** C-22's directive, plus the blank line Tombi requires. @public */
|
|
25
|
-
const SCHEMA_DIRECTIVE =
|
|
41
|
+
const SCHEMA_DIRECTIVE = `#:schema ${okfitConfigSchemaHost.$id}\n\n`;
|
|
26
42
|
/**
|
|
27
43
|
* K-23: the THIN override only — never the merged config. `bundle.path` is
|
|
28
44
|
* the bundle root relative to the project root; `extensions: {}` satisfies
|
|
@@ -171,4 +187,4 @@ const files = (options) => Effect.gen(function* () {
|
|
|
171
187
|
});
|
|
172
188
|
|
|
173
189
|
//#endregion
|
|
174
|
-
export { CONFIG_RELATIVE_PATH, PROJECT_CONFIG_NAMES, SCHEMA_DIRECTIVE, configValue, files, targetPaths };
|
|
190
|
+
export { CONFIG_RELATIVE_PATH, PROJECT_CONFIG_NAMES, SCHEMA_DIRECTIVE, configValue, files, okfitConfigSchemaHost, targetPaths };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@okfit/engine",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.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": [
|
|
@@ -35,19 +35,20 @@
|
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@effect/platform-node": "4.0.0-rc.115",
|
|
38
|
-
"@effected/app": "^0.16.
|
|
39
|
-
"@effected/config-file": "^0.
|
|
38
|
+
"@effected/app": "^0.16.2",
|
|
39
|
+
"@effected/config-file": "^0.10.0",
|
|
40
40
|
"@effected/git": "^0.15.1",
|
|
41
41
|
"@effected/glob": "^0.6.0",
|
|
42
42
|
"@effected/jsonc": "^0.11.0",
|
|
43
43
|
"@effected/markdown": "^0.10.0",
|
|
44
|
+
"@effected/schemastore": "^0.12.0",
|
|
44
45
|
"@effected/store": "^0.8.0",
|
|
45
46
|
"@effected/toml": "^0.7.0",
|
|
46
47
|
"@effected/walker": "^0.9.0",
|
|
47
|
-
"@effected/xdg": "^0.5.
|
|
48
|
+
"@effected/xdg": "^0.5.2",
|
|
48
49
|
"@effected/yaml": "^0.15.1",
|
|
49
|
-
"@okfit/core": "0.
|
|
50
|
-
"@okfit/profiles": "0.
|
|
50
|
+
"@okfit/core": "0.6.0",
|
|
51
|
+
"@okfit/profiles": "0.7.1",
|
|
51
52
|
"effect": "4.0.0-rc.115"
|
|
52
53
|
},
|
|
53
54
|
"engines": {
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Diagnostic, OkfitConfig } from "@okfit/core";
|
|
2
|
+
import { Effect, FileSystem, Path } from "effect";
|
|
3
|
+
|
|
4
|
+
//#region src/validate/resources.ts
|
|
5
|
+
/** A `resource`/`sources[].resource` value that names a URL, not a bundle-relative path (D-24). */
|
|
6
|
+
const SCHEME_RE = /^[a-zA-Z][a-zA-Z0-9+.-]*:/;
|
|
7
|
+
/** Glob metacharacters that mark a value as a descriptor pattern, not a literal path. */
|
|
8
|
+
const GLOB_RE = /[*?[{]/;
|
|
9
|
+
/**
|
|
10
|
+
* True when `value` is a descriptor (a URL, a scope description, or a glob
|
|
11
|
+
* pattern) rather than a literal bundle-relative path — D-24 leaves
|
|
12
|
+
* `Source.resource` untyped for exactly this reason: "a URL, a bundle path or
|
|
13
|
+
* a scope descriptor; never resolved here". Anything with a URL scheme
|
|
14
|
+
* (`https:`, `git:`, …) or a bare `://`, anything containing whitespace (a
|
|
15
|
+
* prose description like "the git history"), and anything containing a glob
|
|
16
|
+
* metacharacter (`src/**`) is a descriptor and is skipped, never resolved
|
|
17
|
+
* against the filesystem.
|
|
18
|
+
*/
|
|
19
|
+
const isDescriptor = (value) => SCHEME_RE.test(value) || value.includes("://") || /\s/.test(value) || GLOB_RE.test(value);
|
|
20
|
+
/** Strips a trailing `#fragment` or `?query` suffix before filesystem resolution. */
|
|
21
|
+
const stripSuffix = (value) => {
|
|
22
|
+
const at = value.search(/[?#]/);
|
|
23
|
+
return at === -1 ? value : value.slice(0, at);
|
|
24
|
+
};
|
|
25
|
+
/** Every `resource` value on a concept: the top-level field, then each source's. */
|
|
26
|
+
const resourceValuesOf = (concept) => {
|
|
27
|
+
const values = [];
|
|
28
|
+
if (concept.frontmatter.resource !== void 0) values.push(concept.frontmatter.resource);
|
|
29
|
+
for (const source of concept.frontmatter.sources ?? []) values.push(source.resource);
|
|
30
|
+
return values;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* D-24's `resource`/`sources[].resource` value resolves to nothing in the
|
|
34
|
+
* bundle for every non-descriptor value on every concept (issue #106). A
|
|
35
|
+
* `resource` is a descriptor (a URL, a scope description, or a glob
|
|
36
|
+
* pattern) or a literal path resolved in D-23 order: relative to the
|
|
37
|
+
* concept's own directory, then (for a bare path) relative to the bundle
|
|
38
|
+
* root, or with a leading `/` relative to the bundle root only; only the
|
|
39
|
+
* latter is checked against the filesystem. Total over severity (mirrors
|
|
40
|
+
* `Provenance.lint`'s S-28 posture): returns `[]`, touching neither
|
|
41
|
+
* `FileSystem` nor `Path`, the moment
|
|
42
|
+
* `OkfitConfig.severityFor(config, "source-resource-missing")` is `"off"`.
|
|
43
|
+
*
|
|
44
|
+
* @public
|
|
45
|
+
*/
|
|
46
|
+
const lintResources = (bundle, config) => Effect.gen(function* () {
|
|
47
|
+
const severity = OkfitConfig.severityFor(config, "source-resource-missing");
|
|
48
|
+
if (severity === "off") return [];
|
|
49
|
+
const fs = yield* FileSystem.FileSystem;
|
|
50
|
+
const path = yield* Path.Path;
|
|
51
|
+
const diagnostics = [];
|
|
52
|
+
for (const [, concept] of bundle.concepts) for (const value of resourceValuesOf(concept)) {
|
|
53
|
+
if (isDescriptor(value)) continue;
|
|
54
|
+
const stripped = stripSuffix(value);
|
|
55
|
+
const candidates = stripped.startsWith("/") ? [path.join(bundle.root, stripped.slice(1))] : [path.resolve(bundle.root, path.dirname(concept.path), stripped), ...stripped.startsWith("./") || stripped.startsWith("../") ? [] : [path.resolve(bundle.root, stripped)]];
|
|
56
|
+
let exists = false;
|
|
57
|
+
for (const candidate of candidates) if (yield* fs.exists(candidate)) {
|
|
58
|
+
exists = true;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
if (exists) continue;
|
|
62
|
+
diagnostics.push(Diagnostic.make({
|
|
63
|
+
file: concept.path,
|
|
64
|
+
code: "source-resource-missing",
|
|
65
|
+
severity,
|
|
66
|
+
message: `Resource "${value}" does not exist relative to ${concept.path}`
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
return diagnostics;
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
//#endregion
|
|
73
|
+
export { lintResources };
|
package/validate/run.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { lintResources } from "./resources.js";
|
|
1
2
|
import { Bundle, OkfitConfig, Validate } from "@okfit/core";
|
|
2
3
|
import { Context, Effect, Option } from "effect";
|
|
3
4
|
import { Provenance } from "@okfit/profiles";
|
|
@@ -53,11 +54,16 @@ const run = (options) => Effect.gen(function* () {
|
|
|
53
54
|
onSome: (profile) => profile.check(bundle)
|
|
54
55
|
});
|
|
55
56
|
const provenance = OkfitConfig.severityFor(options.config, "generated-at-drift") === "off" ? [] : yield* Provenance.lint(bundle, options.config, { skipGitTier: options.skipProvenance === true });
|
|
57
|
+
const resources = yield* lintResources(bundle, options.config);
|
|
56
58
|
return {
|
|
57
59
|
bundle,
|
|
58
60
|
report: {
|
|
59
61
|
...report,
|
|
60
|
-
lint: [
|
|
62
|
+
lint: [
|
|
63
|
+
...report.lint,
|
|
64
|
+
...provenance,
|
|
65
|
+
...resources
|
|
66
|
+
]
|
|
61
67
|
},
|
|
62
68
|
profileDiagnostics
|
|
63
69
|
};
|