@okfit/engine 0.2.1 → 0.4.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/graph/run.js +20 -0
- package/index.d.ts +246 -6
- package/index.js +6 -2
- package/init/scaffold.js +2 -2
- package/package.json +9 -9
- package/render/context.js +44 -4
- package/render/graph.js +77 -0
- package/render/json.js +7 -1
- package/render/stale.js +62 -0
- package/stale/run.js +22 -0
package/graph/run.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Bundle, Graph } from "@okfit/core";
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
|
|
4
|
+
//#region src/graph/run.ts
|
|
5
|
+
/**
|
|
6
|
+
* Load the bundle and build its link graph (D-6, D-26). Pure over the
|
|
7
|
+
* loaded bundle once loading succeeds; `okfit graph` always exits `0`.
|
|
8
|
+
*
|
|
9
|
+
* @public
|
|
10
|
+
*/
|
|
11
|
+
const runGraph = (options) => Effect.gen(function* () {
|
|
12
|
+
const bundle = yield* Bundle.load({ root: options.root });
|
|
13
|
+
return {
|
|
14
|
+
bundle,
|
|
15
|
+
graph: Graph.fromBundle(bundle)
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
//#endregion
|
|
20
|
+
export { runGraph };
|
package/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BundleLoadError, ConceptId, Diagnostic, DiagnosticRange, DiagnosticSeverity, LoadedBundle, OkfitConfig, OkfitConfigFile, ValidationReport } from "@okfit/core";
|
|
1
|
+
import { BundleLoadError, ConceptId, Diagnostic, DiagnosticRange, DiagnosticSeverity, GraphLink, GraphNode, LinkGraph, LoadedBundle, OkfitConfig, OkfitConfigFile, StaleConcept, ValidationReport } from "@okfit/core";
|
|
2
2
|
import { Context, Crypto, DateTime, Effect, FileSystem, Layer, Option, Path, PlatformError, Runtime, Schema } from "effect";
|
|
3
3
|
import { AppDirs, Xdg } from "@effected/xdg";
|
|
4
4
|
import { ConfigReadError } from "@effected/config-file";
|
|
@@ -331,6 +331,25 @@ interface ContextResult {
|
|
|
331
331
|
*/
|
|
332
332
|
export declare const runContext: (options: ContextRunOptions) => Effect.Effect<ContextResult, never, FileSystem.FileSystem | Path.Path>;
|
|
333
333
|
//#endregion
|
|
334
|
+
//#region src/graph/run.d.ts
|
|
335
|
+
/** @public */
|
|
336
|
+
interface GraphRunOptions {
|
|
337
|
+
/** Absolute bundle root; `Bundle.load` never reads cwd (D-8). */
|
|
338
|
+
readonly root: string;
|
|
339
|
+
}
|
|
340
|
+
/** @public */
|
|
341
|
+
interface GraphRunResult {
|
|
342
|
+
readonly bundle: LoadedBundle;
|
|
343
|
+
readonly graph: LinkGraph;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Load the bundle and build its link graph (D-6, D-26). Pure over the
|
|
347
|
+
* loaded bundle once loading succeeds; `okfit graph` always exits `0`.
|
|
348
|
+
*
|
|
349
|
+
* @public
|
|
350
|
+
*/
|
|
351
|
+
export declare const runGraph: (options: GraphRunOptions) => Effect.Effect<GraphRunResult, BundleLoadError, FileSystem.FileSystem | Path.Path>;
|
|
352
|
+
//#endregion
|
|
334
353
|
//#region src/init/scaffold.d.ts
|
|
335
354
|
/** `.config/okfit.toml`, relative to the project root (C-10). @public */
|
|
336
355
|
export declare const CONFIG_RELATIVE_PATH = ".config/okfit.toml";
|
|
@@ -418,11 +437,55 @@ export declare const files: (options: ScaffoldOptions) => Effect.Effect<Readonly
|
|
|
418
437
|
export declare const OkfitPlatform: Layer.Layer<AppDirs | Xdg | NodeServices.NodeServices, import("@effected/xdg").XdgEnvError, never>;
|
|
419
438
|
//#endregion
|
|
420
439
|
//#region src/render/context.d.ts
|
|
421
|
-
/** One `
|
|
440
|
+
/** One enumerated value of a `fields[]` entry. @public */
|
|
441
|
+
export declare const ContextFieldValue: Schema.Struct<{
|
|
442
|
+
readonly name: Schema.String;
|
|
443
|
+
readonly description: Schema.String;
|
|
444
|
+
}>;
|
|
445
|
+
/** @public */
|
|
446
|
+
export type ContextFieldValue = typeof ContextFieldValue.Type;
|
|
447
|
+
/**
|
|
448
|
+
* One `types[].fields[]` entry: a `[types.<Name>.fields.<key>]` declaration
|
|
449
|
+
* flattened for a consumer. `values` keeps the declaration's own order (it
|
|
450
|
+
* is a vocabulary, and the config author chose the order); `kind` is
|
|
451
|
+
* `"path"` or `null`.
|
|
452
|
+
*
|
|
453
|
+
* @public
|
|
454
|
+
*/
|
|
455
|
+
export declare const ContextField: Schema.Struct<{
|
|
456
|
+
readonly name: Schema.String;
|
|
457
|
+
readonly description: Schema.String;
|
|
458
|
+
readonly kind: Schema.NullOr<Schema.Literal<"path">>;
|
|
459
|
+
readonly values: Schema.NullOr<Schema.$Array<Schema.Struct<{
|
|
460
|
+
readonly name: Schema.String;
|
|
461
|
+
readonly description: Schema.String;
|
|
462
|
+
}>>>;
|
|
463
|
+
}>;
|
|
464
|
+
/** @public */
|
|
465
|
+
export type ContextField = typeof ContextField.Type;
|
|
466
|
+
/**
|
|
467
|
+
* One `types[]` entry (M-15). `required`, `require_verified` and `fields`
|
|
468
|
+
* carry the constraints `validate` enforces (issue #33): without them an
|
|
469
|
+
* agent learns that `Interface` exists but not that it requires `kind`, nor
|
|
470
|
+
* which values `kind` accepts, until a lint error says so.
|
|
471
|
+
*
|
|
472
|
+
* @public
|
|
473
|
+
*/
|
|
422
474
|
export declare const ContextType: Schema.Struct<{
|
|
423
475
|
readonly name: Schema.String;
|
|
424
476
|
readonly description: Schema.NullOr<Schema.String>;
|
|
425
477
|
readonly guidance: Schema.NullOr<Schema.String>;
|
|
478
|
+
readonly required: Schema.NullOr<Schema.$Array<Schema.String>>;
|
|
479
|
+
readonly require_verified: Schema.NullOr<Schema.Boolean>;
|
|
480
|
+
readonly fields: Schema.$Array<Schema.Struct<{
|
|
481
|
+
readonly name: Schema.String;
|
|
482
|
+
readonly description: Schema.String;
|
|
483
|
+
readonly kind: Schema.NullOr<Schema.Literal<"path">>;
|
|
484
|
+
readonly values: Schema.NullOr<Schema.$Array<Schema.Struct<{
|
|
485
|
+
readonly name: Schema.String;
|
|
486
|
+
readonly description: Schema.String;
|
|
487
|
+
}>>>;
|
|
488
|
+
}>>;
|
|
426
489
|
}>;
|
|
427
490
|
/** @public */
|
|
428
491
|
export type ContextType = typeof ContextType.Type;
|
|
@@ -474,6 +537,17 @@ export declare const ContextEnvelope: Schema.Struct<{
|
|
|
474
537
|
readonly name: Schema.String;
|
|
475
538
|
readonly description: Schema.NullOr<Schema.String>;
|
|
476
539
|
readonly guidance: Schema.NullOr<Schema.String>;
|
|
540
|
+
readonly required: Schema.NullOr<Schema.$Array<Schema.String>>;
|
|
541
|
+
readonly require_verified: Schema.NullOr<Schema.Boolean>;
|
|
542
|
+
readonly fields: Schema.$Array<Schema.Struct<{
|
|
543
|
+
readonly name: Schema.String;
|
|
544
|
+
readonly description: Schema.String;
|
|
545
|
+
readonly kind: Schema.NullOr<Schema.Literal<"path">>;
|
|
546
|
+
readonly values: Schema.NullOr<Schema.$Array<Schema.Struct<{
|
|
547
|
+
readonly name: Schema.String;
|
|
548
|
+
readonly description: Schema.String;
|
|
549
|
+
}>>>;
|
|
550
|
+
}>>;
|
|
477
551
|
}>>;
|
|
478
552
|
readonly tags: Schema.$Array<Schema.Struct<{
|
|
479
553
|
readonly name: Schema.String;
|
|
@@ -571,6 +645,79 @@ export declare const tally: (diagnostics: ReadonlyArray<RenderedDiagnostic>) =>
|
|
|
571
645
|
*/
|
|
572
646
|
export declare const forDiagnostics: (diagnostics: ReadonlyArray<RenderedDiagnostic>) => 0 | 1 | 2;
|
|
573
647
|
//#endregion
|
|
648
|
+
//#region src/render/graph.d.ts
|
|
649
|
+
/** One entry of the `nodes` array. @public */
|
|
650
|
+
export declare const GraphNodeEnvelope: Schema.Struct<{
|
|
651
|
+
readonly id: Schema.String;
|
|
652
|
+
readonly kind: Schema.Literals<readonly ["concept", "file", "missing"]>;
|
|
653
|
+
}>;
|
|
654
|
+
/** @public */
|
|
655
|
+
export type GraphNodeEnvelope = typeof GraphNodeEnvelope.Type;
|
|
656
|
+
/** One entry of the `edges` array; `field` is omitted, never `null` (exactOptionalPropertyTypes). @public */
|
|
657
|
+
export declare const GraphEdgeEnvelope: Schema.Struct<{
|
|
658
|
+
readonly from: Schema.String;
|
|
659
|
+
readonly to: Schema.String;
|
|
660
|
+
readonly source: Schema.Literals<readonly ["body", "frontmatter"]>;
|
|
661
|
+
readonly field: Schema.optionalKey<Schema.String>;
|
|
662
|
+
readonly raw: Schema.String;
|
|
663
|
+
}>;
|
|
664
|
+
/** @public */
|
|
665
|
+
export type GraphEdgeEnvelope = typeof GraphEdgeEnvelope.Type;
|
|
666
|
+
/** @public */
|
|
667
|
+
export declare const GraphSummary: Schema.Struct<{
|
|
668
|
+
readonly nodes: Schema.Number;
|
|
669
|
+
readonly edges: Schema.Number;
|
|
670
|
+
}>;
|
|
671
|
+
/** @public */
|
|
672
|
+
export type GraphSummary = typeof GraphSummary.Type;
|
|
673
|
+
/**
|
|
674
|
+
* `okfit graph --format json`'s envelope, schema 1, snake_case — the same
|
|
675
|
+
* convention as `render/json.ts`'s `JsonEnvelope`. Built from
|
|
676
|
+
* `LinkGraph.nodes`/`LinkGraph.edges` (D-26).
|
|
677
|
+
*
|
|
678
|
+
* @public
|
|
679
|
+
*/
|
|
680
|
+
export declare const GraphEnvelope: Schema.Struct<{
|
|
681
|
+
readonly schema: Schema.Literal<1>;
|
|
682
|
+
readonly okfit_version: Schema.String;
|
|
683
|
+
readonly producer: Schema.String;
|
|
684
|
+
readonly okf_version: Schema.String;
|
|
685
|
+
readonly root: Schema.String;
|
|
686
|
+
readonly profile: Schema.NullOr<Schema.String>;
|
|
687
|
+
readonly summary: Schema.Struct<{
|
|
688
|
+
readonly nodes: Schema.Number;
|
|
689
|
+
readonly edges: Schema.Number;
|
|
690
|
+
}>;
|
|
691
|
+
readonly nodes: Schema.$Array<Schema.Struct<{
|
|
692
|
+
readonly id: Schema.String;
|
|
693
|
+
readonly kind: Schema.Literals<readonly ["concept", "file", "missing"]>;
|
|
694
|
+
}>>;
|
|
695
|
+
readonly edges: Schema.$Array<Schema.Struct<{
|
|
696
|
+
readonly from: Schema.String;
|
|
697
|
+
readonly to: Schema.String;
|
|
698
|
+
readonly source: Schema.Literals<readonly ["body", "frontmatter"]>;
|
|
699
|
+
readonly field: Schema.optionalKey<Schema.String>;
|
|
700
|
+
readonly raw: Schema.String;
|
|
701
|
+
}>>;
|
|
702
|
+
}>;
|
|
703
|
+
/** @public */
|
|
704
|
+
export type GraphEnvelope = typeof GraphEnvelope.Type;
|
|
705
|
+
/**
|
|
706
|
+
* Build the envelope from a loaded `LinkGraph`'s own `nodes`/`edges`
|
|
707
|
+
* arrays.
|
|
708
|
+
*
|
|
709
|
+
* @public
|
|
710
|
+
*/
|
|
711
|
+
export declare const graphEnvelope: (input: {
|
|
712
|
+
readonly okfitVersion: string;
|
|
713
|
+
readonly producer: string;
|
|
714
|
+
readonly okfVersion: string;
|
|
715
|
+
readonly root: string;
|
|
716
|
+
readonly profile: string | null;
|
|
717
|
+
readonly nodes: ReadonlyArray<GraphNode>;
|
|
718
|
+
readonly edges: ReadonlyArray<GraphLink>;
|
|
719
|
+
}) => GraphEnvelope;
|
|
720
|
+
//#endregion
|
|
574
721
|
//#region src/render/json.d.ts
|
|
575
722
|
/** One entry of the `diagnostics` array (K-21). @public */
|
|
576
723
|
export declare const JsonDiagnostic: Schema.Struct<{
|
|
@@ -597,13 +744,18 @@ export type JsonSummary = typeof JsonSummary.Type;
|
|
|
597
744
|
/**
|
|
598
745
|
* K-21's success envelope, snake_case. `exit_code` is `0 | 1 | 2` only: an
|
|
599
746
|
* infrastructure failure never produces this envelope, it produces the
|
|
600
|
-
* `JsonErrorEnvelope` (K-22).
|
|
747
|
+
* `JsonErrorEnvelope` (K-22). `okfit_version` names the version of the
|
|
748
|
+
* package that produced the report (J-2), so the CLI and the MCP server
|
|
749
|
+
* legitimately report different numbers over one bundle; `producer` names
|
|
750
|
+
* that package (`okfit` or `@okfit/mcp`) so the difference reads as two
|
|
751
|
+
* producers, not as drift (okfit #75).
|
|
601
752
|
*
|
|
602
753
|
* @public
|
|
603
754
|
*/
|
|
604
755
|
export declare const JsonEnvelope: Schema.Struct<{
|
|
605
756
|
readonly schema: Schema.Literal<1>;
|
|
606
757
|
readonly okfit_version: Schema.String;
|
|
758
|
+
readonly producer: Schema.String;
|
|
607
759
|
readonly okf_version: Schema.String;
|
|
608
760
|
readonly root: Schema.String;
|
|
609
761
|
readonly profile: Schema.NullOr<Schema.String>;
|
|
@@ -652,6 +804,7 @@ export type JsonErrorEnvelope = typeof JsonErrorEnvelope.Type;
|
|
|
652
804
|
*/
|
|
653
805
|
export declare const json: (input: {
|
|
654
806
|
readonly okfitVersion: string;
|
|
807
|
+
readonly producer: string;
|
|
655
808
|
readonly okfVersion: string;
|
|
656
809
|
readonly root: string;
|
|
657
810
|
readonly profile: string | null;
|
|
@@ -662,6 +815,69 @@ export declare const json: (input: {
|
|
|
662
815
|
/** K-22. `tag` is the error's `_tag` when it has one, else its constructor name. @public */
|
|
663
816
|
export declare const jsonError: (error: unknown, okfitVersion: string) => JsonErrorEnvelope;
|
|
664
817
|
//#endregion
|
|
818
|
+
//#region src/render/stale.d.ts
|
|
819
|
+
/** One entry of the `items` array. @public */
|
|
820
|
+
export declare const StaleItem: Schema.Struct<{
|
|
821
|
+
readonly id: Schema.String;
|
|
822
|
+
readonly stale_after: Schema.String;
|
|
823
|
+
readonly days_past: Schema.Number;
|
|
824
|
+
}>;
|
|
825
|
+
/** @public */
|
|
826
|
+
export type StaleItem = typeof StaleItem.Type;
|
|
827
|
+
/** @public */
|
|
828
|
+
export declare const StaleSummary: Schema.Struct<{
|
|
829
|
+
readonly concepts: Schema.Number;
|
|
830
|
+
readonly stale: Schema.Number;
|
|
831
|
+
}>;
|
|
832
|
+
/** @public */
|
|
833
|
+
export type StaleSummary = typeof StaleSummary.Type;
|
|
834
|
+
/**
|
|
835
|
+
* `okfit stale --format json`'s envelope, schema 1, snake_case — the same
|
|
836
|
+
* convention as `render/json.ts`'s `JsonEnvelope`. `as_of` and each item's
|
|
837
|
+
* `stale_after` are `DateTime.formatIso` strings (mirrors
|
|
838
|
+
* `packages/mcp/src/tools/staleReport.ts`). `stale` is always `0` (the
|
|
839
|
+
* report never fails a run).
|
|
840
|
+
*
|
|
841
|
+
* @public
|
|
842
|
+
*/
|
|
843
|
+
export declare const StaleEnvelope: Schema.Struct<{
|
|
844
|
+
readonly schema: Schema.Literal<1>;
|
|
845
|
+
readonly okfit_version: Schema.String;
|
|
846
|
+
readonly producer: Schema.String;
|
|
847
|
+
readonly okf_version: Schema.String;
|
|
848
|
+
readonly root: Schema.String;
|
|
849
|
+
readonly profile: Schema.NullOr<Schema.String>;
|
|
850
|
+
readonly as_of: Schema.String;
|
|
851
|
+
readonly summary: Schema.Struct<{
|
|
852
|
+
readonly concepts: Schema.Number;
|
|
853
|
+
readonly stale: Schema.Number;
|
|
854
|
+
}>;
|
|
855
|
+
readonly items: Schema.$Array<Schema.Struct<{
|
|
856
|
+
readonly id: Schema.String;
|
|
857
|
+
readonly stale_after: Schema.String;
|
|
858
|
+
readonly days_past: Schema.Number;
|
|
859
|
+
}>>;
|
|
860
|
+
}>;
|
|
861
|
+
/** @public */
|
|
862
|
+
export type StaleEnvelope = typeof StaleEnvelope.Type;
|
|
863
|
+
/**
|
|
864
|
+
* Build the envelope. `items` is `Derive.staleReport`'s output verbatim
|
|
865
|
+
* (already sorted by id); this just reshapes it to snake_case and formats
|
|
866
|
+
* the two `DateTime.Utc` fields.
|
|
867
|
+
*
|
|
868
|
+
* @public
|
|
869
|
+
*/
|
|
870
|
+
export declare const staleEnvelope: (input: {
|
|
871
|
+
readonly okfitVersion: string;
|
|
872
|
+
readonly producer: string;
|
|
873
|
+
readonly okfVersion: string;
|
|
874
|
+
readonly root: string;
|
|
875
|
+
readonly profile: string | null;
|
|
876
|
+
readonly now: DateTime.Utc;
|
|
877
|
+
readonly concepts: number;
|
|
878
|
+
readonly items: ReadonlyArray<StaleConcept>;
|
|
879
|
+
}) => StaleEnvelope;
|
|
880
|
+
//#endregion
|
|
665
881
|
//#region src/sync/run.d.ts
|
|
666
882
|
/** The three families `okfit sync` regenerates (contract §5). @public */
|
|
667
883
|
type SyncMode = "generated" | "index" | "log";
|
|
@@ -831,6 +1047,30 @@ export declare const verifyEnvelope: (input: {
|
|
|
831
1047
|
readonly dryRun: boolean;
|
|
832
1048
|
}) => VerifyEnvelope;
|
|
833
1049
|
//#endregion
|
|
1050
|
+
//#region src/stale/run.d.ts
|
|
1051
|
+
/** @public */
|
|
1052
|
+
interface StaleRunOptions {
|
|
1053
|
+
/** Absolute bundle root; `Bundle.load` never reads cwd (D-8). */
|
|
1054
|
+
readonly root: string;
|
|
1055
|
+
/** `OKFIT_NOW` or `DateTime.now`, from the caller's own `Now` service (K-47). */
|
|
1056
|
+
readonly now: DateTime.Utc;
|
|
1057
|
+
}
|
|
1058
|
+
/** @public */
|
|
1059
|
+
interface StaleRunResult {
|
|
1060
|
+
readonly bundle: LoadedBundle;
|
|
1061
|
+
/** `Derive.staleReport`'s output verbatim: every stale concept, sorted by id. */
|
|
1062
|
+
readonly items: ReadonlyArray<StaleConcept>;
|
|
1063
|
+
}
|
|
1064
|
+
/**
|
|
1065
|
+
* Load the bundle and derive the stale report against `now` (D-10, D-36:
|
|
1066
|
+
* `Derive.staleReport` is pure and takes `now` as an argument, never a
|
|
1067
|
+
* clock). This is a report, not a check — `okfit stale` always exits `0`;
|
|
1068
|
+
* the `stale` lint rule is where staleness fails a run.
|
|
1069
|
+
*
|
|
1070
|
+
* @public
|
|
1071
|
+
*/
|
|
1072
|
+
export declare const runStale: (options: StaleRunOptions) => Effect.Effect<StaleRunResult, BundleLoadError, FileSystem.FileSystem | Path.Path>;
|
|
1073
|
+
//#endregion
|
|
834
1074
|
//#region src/validate/run.d.ts
|
|
835
1075
|
declare const Now_base: Context.ServiceClass<Now, "@okfit/engine/Now", DateTime.Utc>;
|
|
836
1076
|
/**
|
|
@@ -869,8 +1109,8 @@ interface RunOptions {
|
|
|
869
1109
|
* default severity. Tier 1 (the pure, in-memory body-digest comparison)
|
|
870
1110
|
* still runs regardless — that is exactly the signal edit time wants,
|
|
871
1111
|
* at the cost of one sha256 over text already in memory. Defaults to
|
|
872
|
-
* `false`; `run` still gates the whole lint call on
|
|
873
|
-
* "off"`, but no longer on this flag.
|
|
1112
|
+
* `false`; `run` still gates the whole lint call on
|
|
1113
|
+
* `severity === "off"`, but no longer on this flag.
|
|
874
1114
|
*/
|
|
875
1115
|
readonly skipProvenance?: boolean;
|
|
876
1116
|
}
|
|
@@ -961,5 +1201,5 @@ export declare const runVerify: (options: VerifyOptions) => Effect.Effect<{
|
|
|
961
1201
|
fragment: string;
|
|
962
1202
|
}, 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>;
|
|
963
1203
|
//#endregion
|
|
964
|
-
export type { ContextResult, ContextRunOptions, DiagnosticSource, DiscoveredConfig, RenderedDiagnostic, ResolveProjectConfigInput, ResolvedProjectConfig, RunOptions, RunResult, ScaffoldFile, ScaffoldOptions, SyncMode, SyncModeResult, SyncOptions, SyncResult, Tally, VerifyOptions, VerifyResult };
|
|
1204
|
+
export type { ContextResult, ContextRunOptions, DiagnosticSource, DiscoveredConfig, GraphRunOptions, GraphRunResult, RenderedDiagnostic, ResolveProjectConfigInput, ResolvedProjectConfig, RunOptions, RunResult, ScaffoldFile, ScaffoldOptions, StaleRunOptions, StaleRunResult, SyncMode, SyncModeResult, SyncOptions, SyncResult, Tally, VerifyOptions, VerifyResult };
|
|
965
1205
|
//# sourceMappingURL=index.d.ts.map
|
package/index.js
CHANGED
|
@@ -3,16 +3,20 @@ import { ConfigMalformedError, ConfigPathNotFoundError, InitOverwriteError, Veri
|
|
|
3
3
|
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
|
+
import { runGraph } from "./graph/run.js";
|
|
6
7
|
import { CONFIG_RELATIVE_PATH, SCHEMA_DIRECTIVE, configValue, files, targetPaths } from "./init/scaffold.js";
|
|
7
8
|
import { OkfitPlatform } from "./platform.js";
|
|
8
|
-
import { ContextEnvelope, ContextTag, ContextType, contextEnvelope } from "./render/context.js";
|
|
9
|
+
import { ContextEnvelope, ContextField, ContextFieldValue, ContextTag, ContextType, contextEnvelope } from "./render/context.js";
|
|
9
10
|
import { forDiagnostics, tally } from "./render/exit.js";
|
|
11
|
+
import { GraphEdgeEnvelope, GraphEnvelope, GraphNodeEnvelope, GraphSummary, graphEnvelope } from "./render/graph.js";
|
|
10
12
|
import { collect, sort } from "./render/sort.js";
|
|
11
13
|
import { JsonDiagnostic, JsonEnvelope, JsonErrorEnvelope, JsonSummary, json, jsonError } from "./render/json.js";
|
|
14
|
+
import { StaleEnvelope, StaleItem, StaleSummary, staleEnvelope } from "./render/stale.js";
|
|
12
15
|
import { SkipReason, runSync } from "./sync/run.js";
|
|
13
16
|
import { SyncEnvelope, SyncModeEnvelope, syncEnvelope } from "./render/sync.js";
|
|
14
17
|
import { VerifyEnvelope, verifyEnvelope } from "./render/verify.js";
|
|
18
|
+
import { runStale } from "./stale/run.js";
|
|
15
19
|
import { Now, run } from "./validate/run.js";
|
|
16
20
|
import { runVerify } from "./verify/run.js";
|
|
17
21
|
|
|
18
|
-
export { CONFIG_RELATIVE_PATH, ConfigMalformedError, ConfigPathNotFoundError, ContextEnvelope, ContextTag, ContextType, DEFAULT_PROFILE_NAME, InitOverwriteError, JsonDiagnostic, JsonEnvelope, JsonErrorEnvelope, JsonSummary, Now, OkfitPlatform, SCHEMA_DIRECTIVE, SkipReason, SyncEnvelope, SyncModeEnvelope, VerifyConceptNotFoundError, VerifyEnvelope, VerifyUnsupportedFrontmatterError, buildConfigLayer, collect, configValue, contextEnvelope, files, forDiagnostics, json, jsonError, provideConfig, resolveBundleRoot, resolveProjectConfig, resolveProjectRoot, run, runContext, runSync, runVerify, sort, 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, provideConfig, resolveBundleRoot, resolveProjectConfig, resolveProjectRoot, run, runContext, runGraph, runStale, runSync, runVerify, sort, staleEnvelope, syncEnvelope, tally, targetPaths, verifyEnvelope };
|
package/init/scaffold.js
CHANGED
|
@@ -145,10 +145,10 @@ const files = (options) => Effect.gen(function* () {
|
|
|
145
145
|
okfVersion: OKF_SPEC_VERSION,
|
|
146
146
|
subdirectories
|
|
147
147
|
});
|
|
148
|
-
const logText = Derive.
|
|
148
|
+
const logText = Derive.renderLog([{
|
|
149
149
|
date: today,
|
|
150
150
|
items: [`Initialized the bundle with the ${profileName} profile`]
|
|
151
|
-
});
|
|
151
|
+
}]);
|
|
152
152
|
const directoryFiles = layout.directories.map((directory) => ({
|
|
153
153
|
path: `${bundleRoot}/${directory.directory}/${layout.root.index}`,
|
|
154
154
|
contents: `# ${capitalize(directory.directory)}\n`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@okfit/engine",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.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,19 @@
|
|
|
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.
|
|
40
|
-
"@effected/git": "^0.15.
|
|
38
|
+
"@effected/app": "^0.16.1",
|
|
39
|
+
"@effected/config-file": "^0.9.0",
|
|
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
44
|
"@effected/store": "^0.8.0",
|
|
45
45
|
"@effected/toml": "^0.7.0",
|
|
46
|
-
"@effected/walker": "^0.
|
|
47
|
-
"@effected/xdg": "^0.5.
|
|
48
|
-
"@effected/yaml": "^0.15.
|
|
49
|
-
"@okfit/core": "0.
|
|
50
|
-
"@okfit/profiles": "0.
|
|
46
|
+
"@effected/walker": "^0.9.0",
|
|
47
|
+
"@effected/xdg": "^0.5.1",
|
|
48
|
+
"@effected/yaml": "^0.15.1",
|
|
49
|
+
"@okfit/core": "0.4.1",
|
|
50
|
+
"@okfit/profiles": "0.5.0",
|
|
51
51
|
"effect": "4.0.0-rc.115"
|
|
52
52
|
},
|
|
53
53
|
"engines": {
|
package/render/context.js
CHANGED
|
@@ -1,11 +1,40 @@
|
|
|
1
1
|
import { Schema } from "effect";
|
|
2
2
|
|
|
3
3
|
//#region src/render/context.ts
|
|
4
|
-
/** One `
|
|
4
|
+
/** One enumerated value of a `fields[]` entry. @public */
|
|
5
|
+
const ContextFieldValue = Schema.Struct({
|
|
6
|
+
name: Schema.String,
|
|
7
|
+
description: Schema.String
|
|
8
|
+
});
|
|
9
|
+
/**
|
|
10
|
+
* One `types[].fields[]` entry: a `[types.<Name>.fields.<key>]` declaration
|
|
11
|
+
* flattened for a consumer. `values` keeps the declaration's own order (it
|
|
12
|
+
* is a vocabulary, and the config author chose the order); `kind` is
|
|
13
|
+
* `"path"` or `null`.
|
|
14
|
+
*
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
const ContextField = Schema.Struct({
|
|
18
|
+
name: Schema.String,
|
|
19
|
+
description: Schema.String,
|
|
20
|
+
kind: Schema.NullOr(Schema.Literal("path")),
|
|
21
|
+
values: Schema.NullOr(Schema.Array(ContextFieldValue))
|
|
22
|
+
});
|
|
23
|
+
/**
|
|
24
|
+
* One `types[]` entry (M-15). `required`, `require_verified` and `fields`
|
|
25
|
+
* carry the constraints `validate` enforces (issue #33): without them an
|
|
26
|
+
* agent learns that `Interface` exists but not that it requires `kind`, nor
|
|
27
|
+
* which values `kind` accepts, until a lint error says so.
|
|
28
|
+
*
|
|
29
|
+
* @public
|
|
30
|
+
*/
|
|
5
31
|
const ContextType = Schema.Struct({
|
|
6
32
|
name: Schema.String,
|
|
7
33
|
description: Schema.NullOr(Schema.String),
|
|
8
|
-
guidance: Schema.NullOr(Schema.String)
|
|
34
|
+
guidance: Schema.NullOr(Schema.String),
|
|
35
|
+
required: Schema.NullOr(Schema.Array(Schema.String)),
|
|
36
|
+
require_verified: Schema.NullOr(Schema.Boolean),
|
|
37
|
+
fields: Schema.Array(ContextField)
|
|
9
38
|
});
|
|
10
39
|
/** One `tags[]` entry (M-15). @public */
|
|
11
40
|
const ContextTag = Schema.Struct({
|
|
@@ -71,7 +100,18 @@ const contextEnvelope = (input) => ({
|
|
|
71
100
|
types: Object.entries(input.config.types ?? {}).map(([name, decl]) => ({
|
|
72
101
|
name,
|
|
73
102
|
description: decl.description ?? null,
|
|
74
|
-
guidance: decl.guidance ?? null
|
|
103
|
+
guidance: decl.guidance ?? null,
|
|
104
|
+
required: decl.required ?? null,
|
|
105
|
+
require_verified: decl.require_verified ?? null,
|
|
106
|
+
fields: Object.entries(decl.fields ?? {}).map(([fieldName, field]) => ({
|
|
107
|
+
name: fieldName,
|
|
108
|
+
description: field.description,
|
|
109
|
+
kind: field.kind ?? null,
|
|
110
|
+
values: field.values === void 0 ? null : Object.entries(field.values).map(([valueName, description]) => ({
|
|
111
|
+
name: valueName,
|
|
112
|
+
description
|
|
113
|
+
}))
|
|
114
|
+
})).toSorted((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0)
|
|
75
115
|
})).toSorted((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0),
|
|
76
116
|
tags: Object.entries(input.config.tags ?? {}).map(([name, decl]) => ({
|
|
77
117
|
name,
|
|
@@ -80,4 +120,4 @@ const contextEnvelope = (input) => ({
|
|
|
80
120
|
});
|
|
81
121
|
|
|
82
122
|
//#endregion
|
|
83
|
-
export { ContextEnvelope, ContextTag, ContextType, contextEnvelope };
|
|
123
|
+
export { ContextEnvelope, ContextField, ContextFieldValue, ContextTag, ContextType, contextEnvelope };
|
package/render/graph.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
|
|
3
|
+
//#region src/render/graph.ts
|
|
4
|
+
/** One entry of the `nodes` array. @public */
|
|
5
|
+
const GraphNodeEnvelope = Schema.Struct({
|
|
6
|
+
id: Schema.String,
|
|
7
|
+
kind: Schema.Literals([
|
|
8
|
+
"concept",
|
|
9
|
+
"file",
|
|
10
|
+
"missing"
|
|
11
|
+
])
|
|
12
|
+
});
|
|
13
|
+
/** One entry of the `edges` array; `field` is omitted, never `null` (exactOptionalPropertyTypes). @public */
|
|
14
|
+
const GraphEdgeEnvelope = Schema.Struct({
|
|
15
|
+
from: Schema.String,
|
|
16
|
+
to: Schema.String,
|
|
17
|
+
source: Schema.Literals(["body", "frontmatter"]),
|
|
18
|
+
field: Schema.optionalKey(Schema.String),
|
|
19
|
+
raw: Schema.String
|
|
20
|
+
});
|
|
21
|
+
/** @public */
|
|
22
|
+
const GraphSummary = Schema.Struct({
|
|
23
|
+
nodes: Schema.Number,
|
|
24
|
+
edges: Schema.Number
|
|
25
|
+
});
|
|
26
|
+
/**
|
|
27
|
+
* `okfit graph --format json`'s envelope, schema 1, snake_case — the same
|
|
28
|
+
* convention as `render/json.ts`'s `JsonEnvelope`. Built from
|
|
29
|
+
* `LinkGraph.nodes`/`LinkGraph.edges` (D-26).
|
|
30
|
+
*
|
|
31
|
+
* @public
|
|
32
|
+
*/
|
|
33
|
+
const GraphEnvelope = Schema.Struct({
|
|
34
|
+
schema: Schema.Literal(1),
|
|
35
|
+
okfit_version: Schema.String,
|
|
36
|
+
producer: Schema.String,
|
|
37
|
+
okf_version: Schema.String,
|
|
38
|
+
root: Schema.String,
|
|
39
|
+
profile: Schema.NullOr(Schema.String),
|
|
40
|
+
summary: GraphSummary,
|
|
41
|
+
nodes: Schema.Array(GraphNodeEnvelope),
|
|
42
|
+
edges: Schema.Array(GraphEdgeEnvelope)
|
|
43
|
+
});
|
|
44
|
+
const toNode = (node) => ({
|
|
45
|
+
id: node.id,
|
|
46
|
+
kind: node.kind
|
|
47
|
+
});
|
|
48
|
+
const toEdge = (edge) => ({
|
|
49
|
+
from: edge.from,
|
|
50
|
+
to: edge.to,
|
|
51
|
+
source: edge.data.source,
|
|
52
|
+
...edge.data.field === void 0 ? {} : { field: edge.data.field },
|
|
53
|
+
raw: edge.data.raw
|
|
54
|
+
});
|
|
55
|
+
/**
|
|
56
|
+
* Build the envelope from a loaded `LinkGraph`'s own `nodes`/`edges`
|
|
57
|
+
* arrays.
|
|
58
|
+
*
|
|
59
|
+
* @public
|
|
60
|
+
*/
|
|
61
|
+
const graphEnvelope = (input) => ({
|
|
62
|
+
schema: 1,
|
|
63
|
+
okfit_version: input.okfitVersion,
|
|
64
|
+
producer: input.producer,
|
|
65
|
+
okf_version: input.okfVersion,
|
|
66
|
+
root: input.root,
|
|
67
|
+
profile: input.profile,
|
|
68
|
+
summary: {
|
|
69
|
+
nodes: input.nodes.length,
|
|
70
|
+
edges: input.edges.length
|
|
71
|
+
},
|
|
72
|
+
nodes: input.nodes.map(toNode),
|
|
73
|
+
edges: input.edges.map(toEdge)
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
//#endregion
|
|
77
|
+
export { GraphEdgeEnvelope, GraphEnvelope, GraphNodeEnvelope, GraphSummary, graphEnvelope };
|
package/render/json.js
CHANGED
|
@@ -29,13 +29,18 @@ const JsonSummary = Schema.Struct({
|
|
|
29
29
|
/**
|
|
30
30
|
* K-21's success envelope, snake_case. `exit_code` is `0 | 1 | 2` only: an
|
|
31
31
|
* infrastructure failure never produces this envelope, it produces the
|
|
32
|
-
* `JsonErrorEnvelope` (K-22).
|
|
32
|
+
* `JsonErrorEnvelope` (K-22). `okfit_version` names the version of the
|
|
33
|
+
* package that produced the report (J-2), so the CLI and the MCP server
|
|
34
|
+
* legitimately report different numbers over one bundle; `producer` names
|
|
35
|
+
* that package (`okfit` or `@okfit/mcp`) so the difference reads as two
|
|
36
|
+
* producers, not as drift (okfit #75).
|
|
33
37
|
*
|
|
34
38
|
* @public
|
|
35
39
|
*/
|
|
36
40
|
const JsonEnvelope = Schema.Struct({
|
|
37
41
|
schema: Schema.Literal(1),
|
|
38
42
|
okfit_version: Schema.String,
|
|
43
|
+
producer: Schema.String,
|
|
39
44
|
okf_version: Schema.String,
|
|
40
45
|
root: Schema.String,
|
|
41
46
|
profile: Schema.NullOr(Schema.String),
|
|
@@ -81,6 +86,7 @@ const json = (input) => {
|
|
|
81
86
|
return {
|
|
82
87
|
schema: 1,
|
|
83
88
|
okfit_version: input.okfitVersion,
|
|
89
|
+
producer: input.producer,
|
|
84
90
|
okf_version: input.okfVersion,
|
|
85
91
|
root: input.root,
|
|
86
92
|
profile: input.profile,
|
package/render/stale.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { DateTime, Schema } from "effect";
|
|
2
|
+
|
|
3
|
+
//#region src/render/stale.ts
|
|
4
|
+
/** One entry of the `items` array. @public */
|
|
5
|
+
const StaleItem = Schema.Struct({
|
|
6
|
+
id: Schema.String,
|
|
7
|
+
stale_after: Schema.String,
|
|
8
|
+
days_past: Schema.Number
|
|
9
|
+
});
|
|
10
|
+
/** @public */
|
|
11
|
+
const StaleSummary = Schema.Struct({
|
|
12
|
+
concepts: Schema.Number,
|
|
13
|
+
stale: Schema.Number
|
|
14
|
+
});
|
|
15
|
+
/**
|
|
16
|
+
* `okfit stale --format json`'s envelope, schema 1, snake_case — the same
|
|
17
|
+
* convention as `render/json.ts`'s `JsonEnvelope`. `as_of` and each item's
|
|
18
|
+
* `stale_after` are `DateTime.formatIso` strings (mirrors
|
|
19
|
+
* `packages/mcp/src/tools/staleReport.ts`). `stale` is always `0` (the
|
|
20
|
+
* report never fails a run).
|
|
21
|
+
*
|
|
22
|
+
* @public
|
|
23
|
+
*/
|
|
24
|
+
const StaleEnvelope = Schema.Struct({
|
|
25
|
+
schema: Schema.Literal(1),
|
|
26
|
+
okfit_version: Schema.String,
|
|
27
|
+
producer: Schema.String,
|
|
28
|
+
okf_version: Schema.String,
|
|
29
|
+
root: Schema.String,
|
|
30
|
+
profile: Schema.NullOr(Schema.String),
|
|
31
|
+
as_of: Schema.String,
|
|
32
|
+
summary: StaleSummary,
|
|
33
|
+
items: Schema.Array(StaleItem)
|
|
34
|
+
});
|
|
35
|
+
/**
|
|
36
|
+
* Build the envelope. `items` is `Derive.staleReport`'s output verbatim
|
|
37
|
+
* (already sorted by id); this just reshapes it to snake_case and formats
|
|
38
|
+
* the two `DateTime.Utc` fields.
|
|
39
|
+
*
|
|
40
|
+
* @public
|
|
41
|
+
*/
|
|
42
|
+
const staleEnvelope = (input) => ({
|
|
43
|
+
schema: 1,
|
|
44
|
+
okfit_version: input.okfitVersion,
|
|
45
|
+
producer: input.producer,
|
|
46
|
+
okf_version: input.okfVersion,
|
|
47
|
+
root: input.root,
|
|
48
|
+
profile: input.profile,
|
|
49
|
+
as_of: DateTime.formatIso(input.now),
|
|
50
|
+
summary: {
|
|
51
|
+
concepts: input.concepts,
|
|
52
|
+
stale: input.items.length
|
|
53
|
+
},
|
|
54
|
+
items: input.items.map((item) => ({
|
|
55
|
+
id: item.id,
|
|
56
|
+
stale_after: DateTime.formatIso(item.staleAfter),
|
|
57
|
+
days_past: item.daysPast
|
|
58
|
+
}))
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
//#endregion
|
|
62
|
+
export { StaleEnvelope, StaleItem, StaleSummary, staleEnvelope };
|
package/stale/run.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Bundle, Derive } from "@okfit/core";
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
|
|
4
|
+
//#region src/stale/run.ts
|
|
5
|
+
/**
|
|
6
|
+
* Load the bundle and derive the stale report against `now` (D-10, D-36:
|
|
7
|
+
* `Derive.staleReport` is pure and takes `now` as an argument, never a
|
|
8
|
+
* clock). This is a report, not a check — `okfit stale` always exits `0`;
|
|
9
|
+
* the `stale` lint rule is where staleness fails a run.
|
|
10
|
+
*
|
|
11
|
+
* @public
|
|
12
|
+
*/
|
|
13
|
+
const runStale = (options) => Effect.gen(function* () {
|
|
14
|
+
const bundle = yield* Bundle.load({ root: options.root });
|
|
15
|
+
return {
|
|
16
|
+
bundle,
|
|
17
|
+
items: Derive.staleReport(bundle, options.now)
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
//#endregion
|
|
22
|
+
export { runStale };
|