@davidorex/pi-context 0.28.1 → 0.30.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/CHANGELOG.md +32 -0
- package/README.md +28 -16
- package/dist/block-api.d.ts +12 -3
- package/dist/block-api.d.ts.map +1 -1
- package/dist/block-api.js +16 -5
- package/dist/block-api.js.map +1 -1
- package/dist/context-sdk.d.ts +111 -8
- package/dist/context-sdk.d.ts.map +1 -1
- package/dist/context-sdk.js +191 -15
- package/dist/context-sdk.js.map +1 -1
- package/dist/context.d.ts +103 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +171 -15
- package/dist/context.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +42 -7
- package/dist/index.js.map +1 -1
- package/dist/ops-registry.d.ts +180 -4
- package/dist/ops-registry.d.ts.map +1 -1
- package/dist/ops-registry.js +535 -112
- package/dist/ops-registry.js.map +1 -1
- package/dist/read-element.d.ts +48 -0
- package/dist/read-element.d.ts.map +1 -1
- package/dist/read-element.js +88 -30
- package/dist/read-element.js.map +1 -1
- package/dist/write-schema-migration-tool.d.ts +2 -1
- package/dist/write-schema-migration-tool.d.ts.map +1 -1
- package/dist/write-schema-migration-tool.js +13 -10
- package/dist/write-schema-migration-tool.js.map +1 -1
- package/package.json +1 -1
- package/skills/pi-context/SKILL.md +62 -7
package/dist/context-sdk.d.ts
CHANGED
|
@@ -116,11 +116,16 @@ export interface CurrentState {
|
|
|
116
116
|
}[];
|
|
117
117
|
}
|
|
118
118
|
/**
|
|
119
|
-
* The
|
|
119
|
+
* The five-state bootstrap progression, derived purely from the filesystem
|
|
120
120
|
* (DEC-0040 — nothing stored). Consumed by the `/context start` conductor, the
|
|
121
121
|
* dispatch READY-gate, and the startup-slot hint (DEC-0042 / FGAP-095).
|
|
122
|
+
*
|
|
123
|
+
* `skeleton` (FGAP-001 / DEC-0001) sits between `no-config` and `not-installed`:
|
|
124
|
+
* init / switch -c now write a minimal schema-valid config empty of vocabulary,
|
|
125
|
+
* so a freshly-bootstrapped substrate lands at `skeleton` rather than `no-config`
|
|
126
|
+
* — onward paths are accept-all (adopt the packaged catalog) OR amend/edit.
|
|
122
127
|
*/
|
|
123
|
-
export type BootstrapState = "no-pointer" | "no-config" | "not-installed" | "ready";
|
|
128
|
+
export type BootstrapState = "no-pointer" | "no-config" | "skeleton" | "not-installed" | "ready";
|
|
124
129
|
export interface BootstrapStatus {
|
|
125
130
|
/** which stop in the bootstrap progression `cwd` is at */
|
|
126
131
|
state: BootstrapState;
|
|
@@ -138,11 +143,14 @@ export interface BootstrapStatus {
|
|
|
138
143
|
* pre-bootstrap — it is the unset-substrate detection read the
|
|
139
144
|
* harness-confined LLM uses to redirect the human to `/context start`)
|
|
140
145
|
* no-config — pointer present, no `config.json`
|
|
141
|
-
*
|
|
146
|
+
* skeleton — config present but empty of vocabulary (the init / switch -c
|
|
147
|
+
* minimal config — FGAP-001 / DEC-0001); onward via accept-all
|
|
148
|
+
* OR amend/edit
|
|
149
|
+
* not-installed — config present + populated, some declared installed_* asset is absent
|
|
142
150
|
* ready — config present, all declared assets materialized (or none declared)
|
|
143
151
|
*
|
|
144
152
|
* Does NOT swallow corruption: a malformed `config.json` propagates
|
|
145
|
-
* `loadConfig`'s ValidationError — the
|
|
153
|
+
* `loadConfig`'s ValidationError — the five states are the NORMAL progression;
|
|
146
154
|
* corruption is a separate error condition, not a bootstrap stop.
|
|
147
155
|
*/
|
|
148
156
|
export declare function deriveBootstrapState(cwd: string): BootstrapStatus;
|
|
@@ -465,9 +473,100 @@ export declare function appendRelationByRef(cwd: string, rel: {
|
|
|
465
473
|
child: string;
|
|
466
474
|
relation_type: string;
|
|
467
475
|
ordinal?: number;
|
|
468
|
-
}, ctx?: DispatchContext
|
|
476
|
+
}, ctx?: DispatchContext, opts?: {
|
|
477
|
+
dryRun?: boolean;
|
|
478
|
+
}): {
|
|
469
479
|
appended: boolean;
|
|
470
480
|
edge: Edge;
|
|
481
|
+
dryRun?: boolean;
|
|
482
|
+
};
|
|
483
|
+
/**
|
|
484
|
+
* Friendly-selector relation removal — the porcelain twin of
|
|
485
|
+
* {@link appendRelationByRef}. Resolves `parent` / `child` STRING selectors to
|
|
486
|
+
* structured `EdgeEndpoint`s via the SAME `resolveRelationSelector` the append
|
|
487
|
+
* porcelain uses, then delegates to the raw `removeRelation` plumbing, which
|
|
488
|
+
* matches on the `identityKey` dedup identity (so a `removeRelationByRef` of the
|
|
489
|
+
* selectors an `appendRelationByRef` wrote removes exactly that edge — the
|
|
490
|
+
* porcelain layers stay symmetric). Returns `{ removed, edge }` where `edge` is
|
|
491
|
+
* the RESOLVED structured edge that was matched against (so callers can report /
|
|
492
|
+
* dry-run-validate the structured form), and `removed` is false on the
|
|
493
|
+
* idempotent no-match no-op.
|
|
494
|
+
*/
|
|
495
|
+
export declare function removeRelationByRef(cwd: string, rel: {
|
|
496
|
+
parent: string;
|
|
497
|
+
child: string;
|
|
498
|
+
relation_type: string;
|
|
499
|
+
}, ctx?: DispatchContext, opts?: {
|
|
500
|
+
dryRun?: boolean;
|
|
501
|
+
}): {
|
|
502
|
+
removed: boolean;
|
|
503
|
+
edge: Edge;
|
|
504
|
+
dryRun?: boolean;
|
|
505
|
+
};
|
|
506
|
+
/**
|
|
507
|
+
* Friendly-selector ATOMIC relation replace — a single load → filter-out-old →
|
|
508
|
+
* push-new → write cycle (no half-state: the old edge and the new edge never
|
|
509
|
+
* coexist on disk, and the file is rewritten exactly ONCE). Resolves the `old`
|
|
510
|
+
* and `new` selector triples via the SAME `resolveRelationSelector` the append /
|
|
511
|
+
* remove porcelain use. The old edge is matched on the `identityKey` dedup
|
|
512
|
+
* identity (parent, child, relation_type — `ordinal`-insensitive, symmetric with
|
|
513
|
+
* append-dedup / remove); the new edge is pushed verbatim (carrying its optional
|
|
514
|
+
* `ordinal`). If the resolved new edge collides on identity with a surviving edge
|
|
515
|
+
* it is de-duplicated against the post-filter set so the write stays
|
|
516
|
+
* exact-duplicate-free, matching `appendRelations` semantics.
|
|
517
|
+
*
|
|
518
|
+
* Returns `{ replaced, removed, oldEdge, newEdge }`: `removed` reflects whether
|
|
519
|
+
* the old edge was actually present (false → the old edge was absent, so this is
|
|
520
|
+
* effectively an append of `newEdge`); `replaced` is true when the resolved new
|
|
521
|
+
* edge was written (false only when it collided with an already-present surviving
|
|
522
|
+
* edge → a no-op add). `ctx` threads to `writeRelations` for attestation parity.
|
|
523
|
+
*/
|
|
524
|
+
export declare function replaceRelationByRef(cwd: string, rels: {
|
|
525
|
+
old: {
|
|
526
|
+
parent: string;
|
|
527
|
+
child: string;
|
|
528
|
+
relation_type: string;
|
|
529
|
+
};
|
|
530
|
+
new: {
|
|
531
|
+
parent: string;
|
|
532
|
+
child: string;
|
|
533
|
+
relation_type: string;
|
|
534
|
+
ordinal?: number;
|
|
535
|
+
};
|
|
536
|
+
}, ctx?: DispatchContext, opts?: {
|
|
537
|
+
dryRun?: boolean;
|
|
538
|
+
}): {
|
|
539
|
+
replaced: boolean;
|
|
540
|
+
removed: boolean;
|
|
541
|
+
oldEdge: Edge;
|
|
542
|
+
newEdge: Edge;
|
|
543
|
+
dryRun?: boolean;
|
|
544
|
+
};
|
|
545
|
+
/**
|
|
546
|
+
* Friendly-selector BULK relation append over the raw {@link appendRelations}
|
|
547
|
+
* (whole-file additive write with per-(parent, child, relation_type) dedup,
|
|
548
|
+
* skipping edges already on disk OR earlier in the same batch). Resolves each
|
|
549
|
+
* `edges[]` selector triple via the SAME `resolveRelationSelector` the
|
|
550
|
+
* single-edge porcelain uses, then hands the resolved `Edge[]` to
|
|
551
|
+
* `appendRelations`. Returns `{ appended, skipped, edges }` — `edges` being the
|
|
552
|
+
* resolved structured edges handed to the raw layer (so callers can report /
|
|
553
|
+
* dry-run-validate the structured form). Same deferred-integrity semantics as
|
|
554
|
+
* `appendRelations` (AJV-shape + duplicate-no-op only; relation_type
|
|
555
|
+
* registration / endpoint resolution / cycle checks deferred to
|
|
556
|
+
* `validateContext`).
|
|
557
|
+
*/
|
|
558
|
+
export declare function appendRelationsByRef(cwd: string, edges: {
|
|
559
|
+
parent: string;
|
|
560
|
+
child: string;
|
|
561
|
+
relation_type: string;
|
|
562
|
+
ordinal?: number;
|
|
563
|
+
}[], ctx?: DispatchContext, opts?: {
|
|
564
|
+
dryRun?: boolean;
|
|
565
|
+
}): {
|
|
566
|
+
appended: number;
|
|
567
|
+
skipped: number;
|
|
568
|
+
edges: Edge[];
|
|
569
|
+
dryRun?: boolean;
|
|
471
570
|
};
|
|
472
571
|
/**
|
|
473
572
|
* Classification of an endpoint by {@link resolveRef}:
|
|
@@ -588,8 +687,12 @@ export interface CompleteTaskResult {
|
|
|
588
687
|
}
|
|
589
688
|
/**
|
|
590
689
|
* Gate task completion on verification. Reads the verification block to confirm
|
|
591
|
-
* a passing verification entry exists
|
|
592
|
-
*
|
|
690
|
+
* a passing verification entry exists, asserts a `verification_verifies_item`
|
|
691
|
+
* closure-table edge links that verification (parent) to this task (child), then
|
|
692
|
+
* atomically updates the task status to "completed". The edge IS the linkage —
|
|
693
|
+
* no `verification` field is embedded on the task (the verification → task
|
|
694
|
+
* `verification.target`/`target_type` fields were removed from the verification
|
|
695
|
+
* schema in favor of the edge; this gate reads the edge, not the removed fields).
|
|
593
696
|
*/
|
|
594
|
-
export declare function completeTask(cwd: string, taskId: string, verificationId: string): CompleteTaskResult;
|
|
697
|
+
export declare function completeTask(cwd: string, taskId: string, verificationId: string, ctx?: DispatchContext): CompleteTaskResult;
|
|
595
698
|
//# sourceMappingURL=context-sdk.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-sdk.d.ts","sourceRoot":"","sources":["../src/context-sdk.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"context-sdk.d.ts","sourceRoot":"","sources":["../src/context-sdk.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,EAGN,KAAK,WAAW,EAChB,KAAK,IAAI,EACT,KAAK,YAAY,EAQjB,KAAK,WAAW,EAIhB,MAAM,cAAc,CAAC;AAGtB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAW7D,OAAO,EACN,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,WAAW,EACX,KAAK,IAAI,EACT,KAAK,YAAY,EACjB,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,iBAAiB,EACjB,UAAU,EACV,WAAW,EACX,aAAa,EACb,KAAK,kBAAkB,EACvB,iBAAiB,EACjB,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,EAC9B,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,GACf,MAAM,cAAc,CAAC;AAItB,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,CAcxD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAYtD;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAwBhH;AAID,yEAAyE;AACzE,eAAO,MAAM,mBAAmB,0KAatB,CAAC;AAEX,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC,CAAC;CAClD;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAE7E;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAuD/F;AASD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,EAAE,CAa1D;AAED,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC7C;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,EAAE,CAuB5D;AAID,MAAM,WAAW,YAAY;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CACrC;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC5B,8FAA8F;IAC9F,KAAK,EAAE,MAAM,CAAC;IACd,sCAAsC;IACtC,QAAQ,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC/D,uGAAuG;IACvG,WAAW,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC/E,wFAAwF;IACxF,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAC;CAC9D;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,cAAc,GAAG,YAAY,GAAG,WAAW,GAAG,UAAU,GAAG,eAAe,GAAG,OAAO,CAAC;AAEjG,MAAM,WAAW,eAAe;IAC/B,0DAA0D;IAC1D,KAAK,EAAE,cAAc,CAAC;IACtB,mFAAmF;IACnF,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,oGAAoG;IACpG,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CACjD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,CAgBjE;AAED,MAAM,WAAW,YAAY;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAC7C,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAEhB,YAAY,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;IACvG,KAAK,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;IAC5D,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3B,aAAa,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAClE,UAAU,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CA8OtD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CA+ItD;AAID;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,eAAe;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,SAAS,CAAC;IACpC,KAAK,EAAE,OAAO,CAAC;CACf;AAOD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,eAAe,GAAG,OAAO,EAAE,CAyBtG;AAED,MAAM,WAAW,SAAS;IACzB,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAQxF;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAC5B,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5C,SAAS,CAKX;AAoBD,MAAM,WAAW,QAAQ;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;IAClC,aAAa,CAAC,EAAE,eAAe,CAAC;CAChC;AAED,MAAM,WAAW,UAAU;IAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;CACjC;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,UAAU,EAAE,CAiDpE;AAID;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC5B;;;;;;OAMG;IACH,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,WAAW,cAAc;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACrC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACjC,KAAK,EAAE,YAAY,EAAE,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAkBrF;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CASxD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,GAAG,cAAc,CAmE9G;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAE5E;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC,CAS9F;AAoCD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,CAgCnF;AAuBD;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAClC,GAAG,EAAE,MAAM,EACX,GAAG,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,EAC/E,GAAG,CAAC,EAAE,eAAe,EACrB,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GACzB;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,IAAI,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,CAqBrD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAClC,GAAG,EAAE,MAAM,EACX,GAAG,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,EAC7D,GAAG,CAAC,EAAE,eAAe,EACrB,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GACzB;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,IAAI,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,CAoBpD;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,oBAAoB,CACnC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;IACL,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9D,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAChF,EACD,GAAG,CAAC,EAAE,eAAe,EACrB,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GACzB;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,IAAI,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,CA6BzF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CACnC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,EACnF,GAAG,CAAC,EAAE,eAAe,EACrB,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GACzB;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,IAAI,EAAE,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,CAiCxE;AAID;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,cAAc,CAAC;AAE/E;;;;;;;GAOG;AACH,MAAM,WAAW,WAAW;IAC3B,MAAM,EAAE,aAAa,CAAC;IACtB,YAAY,EAAE,MAAM,GAAG,UAAU,CAAC;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,YAAY,CAAC;CACnB;AAsCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,UAAU,CACzB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,WAAW,EAChB,IAAI,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,cAAc,CAAC;IAAC,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;CAAE,GACjF,WAAW,CA4Fb;AAID,MAAM,WAAW,sBAAsB;IACtC,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,uBAAuB;IACvC,MAAM,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,CAAC;IACzC,MAAM,EAAE,sBAAsB,EAAE,CAAC;CACjC;AAcD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,uBAAuB,CAoXpE;AAID,MAAM,WAAW,kBAAkB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC3B,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,EACtB,GAAG,CAAC,EAAE,eAAe,GACnB,kBAAkB,CAkEpB"}
|
package/dist/context-sdk.js
CHANGED
|
@@ -6,13 +6,16 @@
|
|
|
6
6
|
import { execSync } from "node:child_process";
|
|
7
7
|
import fs from "node:fs";
|
|
8
8
|
import path from "node:path";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
9
10
|
import { readBlock, readBlockForDir, updateItemInBlock } from "./block-api.js";
|
|
10
|
-
import { appendRelation, endpointKey, findUnmaterializedAssets, loadConfig, loadRelations, validateRelations, } from "./context.js";
|
|
11
|
+
import { appendRelation, appendRelations, endpointIdentity, endpointKey, findUnmaterializedAssets, isSkeletonConfig, loadConfig, loadRelations, removeRelation, validateRelations, writeRelations, } from "./context.js";
|
|
11
12
|
import { resolveContextDir, SCHEMAS_DIR, schemaPath, schemasDir, tryResolveContextDir } from "./context-dir.js";
|
|
12
13
|
import { loadRegistry, resolveAlias, resolveSubstrateDir } from "./context-registry.js";
|
|
13
14
|
import { cleanGitEnv } from "./git-env.js";
|
|
14
15
|
import { getLensValidators } from "./lens-validator.js";
|
|
16
|
+
import { findReferencesInRepo } from "./lens-view.js";
|
|
15
17
|
import { addressInto, discoverArrayKey, pageArray } from "./read-element.js";
|
|
18
|
+
import { validateFromFile } from "./schema-validator.js";
|
|
16
19
|
import { findNestedIdBearingArrays } from "./schema-write.js";
|
|
17
20
|
import { resolveStatusVocabulary } from "./status-vocab.js";
|
|
18
21
|
import { topoSort } from "./topo.js";
|
|
@@ -239,11 +242,14 @@ export function blockStructure(cwd) {
|
|
|
239
242
|
* pre-bootstrap — it is the unset-substrate detection read the
|
|
240
243
|
* harness-confined LLM uses to redirect the human to `/context start`)
|
|
241
244
|
* no-config — pointer present, no `config.json`
|
|
242
|
-
*
|
|
245
|
+
* skeleton — config present but empty of vocabulary (the init / switch -c
|
|
246
|
+
* minimal config — FGAP-001 / DEC-0001); onward via accept-all
|
|
247
|
+
* OR amend/edit
|
|
248
|
+
* not-installed — config present + populated, some declared installed_* asset is absent
|
|
243
249
|
* ready — config present, all declared assets materialized (or none declared)
|
|
244
250
|
*
|
|
245
251
|
* Does NOT swallow corruption: a malformed `config.json` propagates
|
|
246
|
-
* `loadConfig`'s ValidationError — the
|
|
252
|
+
* `loadConfig`'s ValidationError — the five states are the NORMAL progression;
|
|
247
253
|
* corruption is a separate error condition, not a bootstrap stop.
|
|
248
254
|
*/
|
|
249
255
|
export function deriveBootstrapState(cwd) {
|
|
@@ -256,6 +262,9 @@ export function deriveBootstrapState(cwd) {
|
|
|
256
262
|
if (config === null) {
|
|
257
263
|
return { state: "no-config", contextDir, missing: empty };
|
|
258
264
|
}
|
|
265
|
+
if (isSkeletonConfig(config)) {
|
|
266
|
+
return { state: "skeleton", contextDir, missing: empty };
|
|
267
|
+
}
|
|
259
268
|
const missing = findUnmaterializedAssets(cwd, config);
|
|
260
269
|
const installed = missing.schemas.length === 0 && missing.blocks.length === 0;
|
|
261
270
|
return { state: installed ? "ready" : "not-installed", contextDir, missing };
|
|
@@ -1105,6 +1114,25 @@ export function resolveRelationSelector(cwd, selector) {
|
|
|
1105
1114
|
const oid = loc && typeof loc.item.oid === "string" ? loc.item.oid : selector;
|
|
1106
1115
|
return { kind: "item", oid, refname: selector };
|
|
1107
1116
|
}
|
|
1117
|
+
/**
|
|
1118
|
+
* Resolve the bundled relations schema file (top-level `Edge[]` array schema)
|
|
1119
|
+
* — the SAME schema `loadRelations` / `writeRelations` validate against (see
|
|
1120
|
+
* `context.ts` `bundledSchemaPath("relations")`). Resolved relative to this
|
|
1121
|
+
* module so it works from both `src/` (tsx --test) and `dist/` (after tsc) —
|
|
1122
|
+
* the `schemas/` dir lives one directory up in either case. Used by the
|
|
1123
|
+
* `dryRun` preview branch of the relation porcelain to apply the write path's
|
|
1124
|
+
* validation WITHOUT writing (TASK-010: the shared library preview the
|
|
1125
|
+
* orchestrator scripts and the `--dryRun` ops both call).
|
|
1126
|
+
*/
|
|
1127
|
+
function relationsSchemaPath() {
|
|
1128
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
1129
|
+
return path.resolve(here, "..", "schemas", "relations.schema.json");
|
|
1130
|
+
}
|
|
1131
|
+
/** Dedup identity key for an edge — the SAME (parent, child, relation_type)
|
|
1132
|
+
* identity the raw append/remove plumbing matches on (ordinal-insensitive). */
|
|
1133
|
+
function edgeIdentityKey(edge) {
|
|
1134
|
+
return `${endpointIdentity(edge.parent)} ${endpointIdentity(edge.child)} ${edge.relation_type}`;
|
|
1135
|
+
}
|
|
1108
1136
|
/**
|
|
1109
1137
|
* Friendly-selector relation append (Cycle 5 porcelain). Resolves `parent` /
|
|
1110
1138
|
* `child` STRING selectors to structured `EdgeEndpoint`s via
|
|
@@ -1117,16 +1145,157 @@ export function resolveRelationSelector(cwd, selector) {
|
|
|
1117
1145
|
* actually written (so callers can report / dry-run-validate the structured
|
|
1118
1146
|
* form).
|
|
1119
1147
|
*/
|
|
1120
|
-
export function appendRelationByRef(cwd, rel, ctx) {
|
|
1148
|
+
export function appendRelationByRef(cwd, rel, ctx, opts) {
|
|
1121
1149
|
const edge = {
|
|
1122
1150
|
parent: resolveRelationSelector(cwd, rel.parent),
|
|
1123
1151
|
child: resolveRelationSelector(cwd, rel.child),
|
|
1124
1152
|
relation_type: rel.relation_type,
|
|
1125
1153
|
...(rel.ordinal !== undefined ? { ordinal: rel.ordinal } : {}),
|
|
1126
1154
|
};
|
|
1155
|
+
if (opts?.dryRun) {
|
|
1156
|
+
// Preview parity: run the SAME validation the write path applies (the
|
|
1157
|
+
// prospective Edge[] against the whole relations schema — what
|
|
1158
|
+
// loadRelations/writeRelations validate) but write nothing. The
|
|
1159
|
+
// would-decision uses the SAME dedup identity the raw append matches on.
|
|
1160
|
+
const existing = loadRelations(cwd);
|
|
1161
|
+
const prospective = [...existing, edge];
|
|
1162
|
+
validateFromFile(relationsSchemaPath(), prospective, "relations[edge]");
|
|
1163
|
+
const newId = edgeIdentityKey(edge);
|
|
1164
|
+
const duplicate = existing.some((e) => edgeIdentityKey(e) === newId);
|
|
1165
|
+
return { appended: !duplicate, edge, dryRun: true };
|
|
1166
|
+
}
|
|
1127
1167
|
const { appended } = appendRelation(cwd, edge, ctx);
|
|
1128
1168
|
return { appended, edge };
|
|
1129
1169
|
}
|
|
1170
|
+
/**
|
|
1171
|
+
* Friendly-selector relation removal — the porcelain twin of
|
|
1172
|
+
* {@link appendRelationByRef}. Resolves `parent` / `child` STRING selectors to
|
|
1173
|
+
* structured `EdgeEndpoint`s via the SAME `resolveRelationSelector` the append
|
|
1174
|
+
* porcelain uses, then delegates to the raw `removeRelation` plumbing, which
|
|
1175
|
+
* matches on the `identityKey` dedup identity (so a `removeRelationByRef` of the
|
|
1176
|
+
* selectors an `appendRelationByRef` wrote removes exactly that edge — the
|
|
1177
|
+
* porcelain layers stay symmetric). Returns `{ removed, edge }` where `edge` is
|
|
1178
|
+
* the RESOLVED structured edge that was matched against (so callers can report /
|
|
1179
|
+
* dry-run-validate the structured form), and `removed` is false on the
|
|
1180
|
+
* idempotent no-match no-op.
|
|
1181
|
+
*/
|
|
1182
|
+
export function removeRelationByRef(cwd, rel, ctx, opts) {
|
|
1183
|
+
const edge = {
|
|
1184
|
+
parent: resolveRelationSelector(cwd, rel.parent),
|
|
1185
|
+
child: resolveRelationSelector(cwd, rel.child),
|
|
1186
|
+
relation_type: rel.relation_type,
|
|
1187
|
+
};
|
|
1188
|
+
if (opts?.dryRun) {
|
|
1189
|
+
// Preview parity: compute the prospective post-removal Edge[] and validate
|
|
1190
|
+
// it against the whole relations schema (write-path validation), write
|
|
1191
|
+
// nothing. `removed` reflects whether a matching edge is present on the
|
|
1192
|
+
// SAME dedup identity the raw remove matches on.
|
|
1193
|
+
const existing = loadRelations(cwd);
|
|
1194
|
+
const targetId = edgeIdentityKey(edge);
|
|
1195
|
+
const matches = existing.some((e) => edgeIdentityKey(e) === targetId);
|
|
1196
|
+
const prospective = existing.filter((e) => edgeIdentityKey(e) !== targetId);
|
|
1197
|
+
validateFromFile(relationsSchemaPath(), prospective, "relations[edge]");
|
|
1198
|
+
return { removed: matches, edge, dryRun: true };
|
|
1199
|
+
}
|
|
1200
|
+
const { removed } = removeRelation(cwd, edge, ctx);
|
|
1201
|
+
return { removed, edge };
|
|
1202
|
+
}
|
|
1203
|
+
/**
|
|
1204
|
+
* Friendly-selector ATOMIC relation replace — a single load → filter-out-old →
|
|
1205
|
+
* push-new → write cycle (no half-state: the old edge and the new edge never
|
|
1206
|
+
* coexist on disk, and the file is rewritten exactly ONCE). Resolves the `old`
|
|
1207
|
+
* and `new` selector triples via the SAME `resolveRelationSelector` the append /
|
|
1208
|
+
* remove porcelain use. The old edge is matched on the `identityKey` dedup
|
|
1209
|
+
* identity (parent, child, relation_type — `ordinal`-insensitive, symmetric with
|
|
1210
|
+
* append-dedup / remove); the new edge is pushed verbatim (carrying its optional
|
|
1211
|
+
* `ordinal`). If the resolved new edge collides on identity with a surviving edge
|
|
1212
|
+
* it is de-duplicated against the post-filter set so the write stays
|
|
1213
|
+
* exact-duplicate-free, matching `appendRelations` semantics.
|
|
1214
|
+
*
|
|
1215
|
+
* Returns `{ replaced, removed, oldEdge, newEdge }`: `removed` reflects whether
|
|
1216
|
+
* the old edge was actually present (false → the old edge was absent, so this is
|
|
1217
|
+
* effectively an append of `newEdge`); `replaced` is true when the resolved new
|
|
1218
|
+
* edge was written (false only when it collided with an already-present surviving
|
|
1219
|
+
* edge → a no-op add). `ctx` threads to `writeRelations` for attestation parity.
|
|
1220
|
+
*/
|
|
1221
|
+
export function replaceRelationByRef(cwd, rels, ctx, opts) {
|
|
1222
|
+
const oldEdge = {
|
|
1223
|
+
parent: resolveRelationSelector(cwd, rels.old.parent),
|
|
1224
|
+
child: resolveRelationSelector(cwd, rels.old.child),
|
|
1225
|
+
relation_type: rels.old.relation_type,
|
|
1226
|
+
};
|
|
1227
|
+
const newEdge = {
|
|
1228
|
+
parent: resolveRelationSelector(cwd, rels.new.parent),
|
|
1229
|
+
child: resolveRelationSelector(cwd, rels.new.child),
|
|
1230
|
+
relation_type: rels.new.relation_type,
|
|
1231
|
+
...(rels.new.ordinal !== undefined ? { ordinal: rels.new.ordinal } : {}),
|
|
1232
|
+
};
|
|
1233
|
+
const existing = loadRelations(cwd);
|
|
1234
|
+
const oldKey = edgeIdentityKey(oldEdge);
|
|
1235
|
+
const newKey = edgeIdentityKey(newEdge);
|
|
1236
|
+
const filtered = existing.filter((e) => edgeIdentityKey(e) !== oldKey);
|
|
1237
|
+
const removed = filtered.length !== existing.length;
|
|
1238
|
+
const collides = filtered.some((e) => edgeIdentityKey(e) === newKey);
|
|
1239
|
+
const next = collides ? filtered : [...filtered, newEdge];
|
|
1240
|
+
if (opts?.dryRun) {
|
|
1241
|
+
// Preview parity: validate the prospective post-replace Edge[] against the
|
|
1242
|
+
// whole relations schema (write-path validation), write nothing. The
|
|
1243
|
+
// would-decisions (`removed`/`replaced`) are the SAME values the write
|
|
1244
|
+
// path computes.
|
|
1245
|
+
validateFromFile(relationsSchemaPath(), next, "relations[edge]");
|
|
1246
|
+
return { replaced: !collides, removed, oldEdge, newEdge, dryRun: true };
|
|
1247
|
+
}
|
|
1248
|
+
writeRelations(cwd, next, ctx);
|
|
1249
|
+
return { replaced: !collides, removed, oldEdge, newEdge };
|
|
1250
|
+
}
|
|
1251
|
+
/**
|
|
1252
|
+
* Friendly-selector BULK relation append over the raw {@link appendRelations}
|
|
1253
|
+
* (whole-file additive write with per-(parent, child, relation_type) dedup,
|
|
1254
|
+
* skipping edges already on disk OR earlier in the same batch). Resolves each
|
|
1255
|
+
* `edges[]` selector triple via the SAME `resolveRelationSelector` the
|
|
1256
|
+
* single-edge porcelain uses, then hands the resolved `Edge[]` to
|
|
1257
|
+
* `appendRelations`. Returns `{ appended, skipped, edges }` — `edges` being the
|
|
1258
|
+
* resolved structured edges handed to the raw layer (so callers can report /
|
|
1259
|
+
* dry-run-validate the structured form). Same deferred-integrity semantics as
|
|
1260
|
+
* `appendRelations` (AJV-shape + duplicate-no-op only; relation_type
|
|
1261
|
+
* registration / endpoint resolution / cycle checks deferred to
|
|
1262
|
+
* `validateContext`).
|
|
1263
|
+
*/
|
|
1264
|
+
export function appendRelationsByRef(cwd, edges, ctx, opts) {
|
|
1265
|
+
const resolved = edges.map((rel) => ({
|
|
1266
|
+
parent: resolveRelationSelector(cwd, rel.parent),
|
|
1267
|
+
child: resolveRelationSelector(cwd, rel.child),
|
|
1268
|
+
relation_type: rel.relation_type,
|
|
1269
|
+
...(rel.ordinal !== undefined ? { ordinal: rel.ordinal } : {}),
|
|
1270
|
+
}));
|
|
1271
|
+
if (opts?.dryRun) {
|
|
1272
|
+
// Preview parity: replay the bulk dedup the raw appendRelations applies —
|
|
1273
|
+
// skip an edge whose identity is already on disk OR earlier in THIS batch
|
|
1274
|
+
// (a `seen` Set seeded from the existing on-disk identities) — accumulate
|
|
1275
|
+
// the non-dup prospective Edge[], validate it against the whole relations
|
|
1276
|
+
// schema (write-path validation), write nothing.
|
|
1277
|
+
const existing = loadRelations(cwd);
|
|
1278
|
+
const seen = new Set(existing.map((e) => edgeIdentityKey(e)));
|
|
1279
|
+
let appended = 0;
|
|
1280
|
+
let skipped = 0;
|
|
1281
|
+
const prospective = [...existing];
|
|
1282
|
+
for (const edge of resolved) {
|
|
1283
|
+
const key = edgeIdentityKey(edge);
|
|
1284
|
+
if (seen.has(key)) {
|
|
1285
|
+
skipped++;
|
|
1286
|
+
}
|
|
1287
|
+
else {
|
|
1288
|
+
seen.add(key);
|
|
1289
|
+
prospective.push(edge);
|
|
1290
|
+
appended++;
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
validateFromFile(relationsSchemaPath(), prospective, "relations[edge]");
|
|
1294
|
+
return { appended, skipped, edges: resolved, dryRun: true };
|
|
1295
|
+
}
|
|
1296
|
+
const { appended, skipped } = appendRelations(cwd, resolved, ctx);
|
|
1297
|
+
return { appended, skipped, edges: resolved };
|
|
1298
|
+
}
|
|
1130
1299
|
/**
|
|
1131
1300
|
* Build (or fetch from the per-pass cache) the {@link SubstrateIndex} for a
|
|
1132
1301
|
* REGISTERED foreign substrate. Resolves the substrate dir from the registry,
|
|
@@ -1704,10 +1873,14 @@ export function validateContext(cwd) {
|
|
|
1704
1873
|
}
|
|
1705
1874
|
/**
|
|
1706
1875
|
* Gate task completion on verification. Reads the verification block to confirm
|
|
1707
|
-
* a passing verification entry exists
|
|
1708
|
-
*
|
|
1876
|
+
* a passing verification entry exists, asserts a `verification_verifies_item`
|
|
1877
|
+
* closure-table edge links that verification (parent) to this task (child), then
|
|
1878
|
+
* atomically updates the task status to "completed". The edge IS the linkage —
|
|
1879
|
+
* no `verification` field is embedded on the task (the verification → task
|
|
1880
|
+
* `verification.target`/`target_type` fields were removed from the verification
|
|
1881
|
+
* schema in favor of the edge; this gate reads the edge, not the removed fields).
|
|
1709
1882
|
*/
|
|
1710
|
-
export function completeTask(cwd, taskId, verificationId) {
|
|
1883
|
+
export function completeTask(cwd, taskId, verificationId, ctx) {
|
|
1711
1884
|
// 1. Read and validate verification entry
|
|
1712
1885
|
let verData;
|
|
1713
1886
|
try {
|
|
@@ -1721,9 +1894,6 @@ export function completeTask(cwd, taskId, verificationId) {
|
|
|
1721
1894
|
if (!verification) {
|
|
1722
1895
|
throw new Error(`Verification '${verificationId}' not found in verification block`);
|
|
1723
1896
|
}
|
|
1724
|
-
if (verification.target !== taskId || verification.target_type !== "task") {
|
|
1725
|
-
throw new Error(`Verification '${verificationId}' targets '${verification.target}' (${verification.target_type}), not task '${taskId}'`);
|
|
1726
|
-
}
|
|
1727
1897
|
if (verification.status !== "passed") {
|
|
1728
1898
|
throw new Error(`Verification '${verificationId}' status is '${verification.status}', not 'passed' — cannot complete task`);
|
|
1729
1899
|
}
|
|
@@ -1747,11 +1917,17 @@ export function completeTask(cwd, taskId, verificationId) {
|
|
|
1747
1917
|
if (currentStatus === "cancelled") {
|
|
1748
1918
|
throw new Error(`Task '${taskId}' is already cancelled`);
|
|
1749
1919
|
}
|
|
1750
|
-
// 3.
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1920
|
+
// 3. Assert the verification_verifies_item edge: verification (parent) →
|
|
1921
|
+
// task (child). The closure-table edge — not a verification field — is the
|
|
1922
|
+
// canonical linkage. Inbound edges point AT the task; compare the parent
|
|
1923
|
+
// endpoint via endpointKey (the codebase's endpoint-comparison idiom).
|
|
1924
|
+
const verifiesEdge = findReferencesInRepo(cwd, taskId, "inbound").find((e) => e.relation_type === "verification_verifies_item" && endpointKey(e.parent) === verificationId);
|
|
1925
|
+
if (!verifiesEdge) {
|
|
1926
|
+
throw new Error(`verification '${verificationId}' does not verify task '${taskId}' — no verification_verifies_item edge; file the link (append-relation parent=${verificationId} child=${taskId} relation_type=verification_verifies_item) before completing`);
|
|
1927
|
+
}
|
|
1928
|
+
// 4. Update task status. The edge is the linkage — no `verification` field is
|
|
1929
|
+
// embedded (a populated additionalProperties:false tasks schema would reject it).
|
|
1930
|
+
updateItemInBlock(cwd, "tasks", "tasks", (t) => t.id === taskId, { status: "completed" }, ctx);
|
|
1755
1931
|
return {
|
|
1756
1932
|
taskId,
|
|
1757
1933
|
verificationId,
|