@rolexjs/core 1.5.0-dev-20260309145703 → 1.5.0-dev-20260310014736

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/dist/index.d.ts CHANGED
@@ -167,6 +167,31 @@ declare const dissolve: _rolexjs_system.Process;
167
167
  declare const abolish: _rolexjs_system.Process;
168
168
  declare const rehire: _rolexjs_system.Process;
169
169
 
170
+ /**
171
+ * Projection — the single projection pipeline for RoleX.
172
+ *
173
+ * Pipeline: raw project → compact(depth) → enrich permissions.
174
+ *
175
+ * All projections go through this pipeline. No special cases.
176
+ * Control behavior via ProjectionContext.
177
+ *
178
+ * Rules:
179
+ * - Root (depth 0): full
180
+ * - Level 1 children: full (with content)
181
+ * - Level 2+ grandchildren: compact (name/id/tag only, no subtree)
182
+ * - Reverse links: compact immediately
183
+ * - Forward links: keep children but strip nested links
184
+ */
185
+
186
+ interface ProjectionContext {
187
+ /** Children expansion depth. Default 1: one level fully expanded, then compact. */
188
+ depth?: number;
189
+ }
190
+ interface Projection {
191
+ /** Project a node through the full pipeline: raw → compact → enrich. */
192
+ (node: Structure, ctx?: ProjectionContext): Promise<State>;
193
+ }
194
+
170
195
  /**
171
196
  * Commands — platform-agnostic command implementations.
172
197
  *
@@ -188,6 +213,7 @@ interface CommandContext {
188
213
  past: Structure;
189
214
  resolve(id: string): Structure | Promise<Structure>;
190
215
  find(id: string): (Structure | null) | Promise<Structure | null>;
216
+ project: Projection;
191
217
  resourcex?: ResourceX;
192
218
  issuex?: IssueX;
193
219
  prototype?: PrototypeRepository;
@@ -414,6 +440,7 @@ interface RoleX {
414
440
  declare class RoleXService implements RoleX {
415
441
  private rt;
416
442
  private commands;
443
+ private project;
417
444
  private resourcex?;
418
445
  private issuex?;
419
446
  private repo;
@@ -438,10 +465,8 @@ declare class RoleXService implements RoleX {
438
465
  direct<T = unknown>(locator: string, args?: Record<string, unknown>, options?: {
439
466
  raw?: boolean;
440
467
  }): Promise<T>;
441
- /** Find a node by id across the entire society tree. */
468
+ /** Find a node by id across the entire society tree (raw, no pipeline). */
442
469
  private find;
443
- /** Find and project a node's full subtree by id. */
444
- private projectById;
445
470
  }
446
471
 
447
472
  /**
package/dist/index.js CHANGED
@@ -654,9 +654,9 @@ async function applyPrototype(data, repo, direct) {
654
654
  import { parse } from "@rolexjs/parser";
655
655
  import { structure as structure2 } from "@rolexjs/system";
656
656
  function createCommands(ctx) {
657
- const { rt, society: society2, past: past2, resolve, resourcex, issuex } = ctx;
657
+ const { rt, society: society2, past: past2, resolve, project: project2, resourcex, issuex } = ctx;
658
658
  async function ok(node, process8) {
659
- return { state: await rt.project(node), process: process8 };
659
+ return { state: await project2(node), process: process8 };
660
660
  }
661
661
  async function archive2(node, process8) {
662
662
  const target = structure2(node.name, node.description ?? "", past);
@@ -848,14 +848,14 @@ ${text}`;
848
848
  if (org) await rt.link(node, await resolve(org), "ownership", "project");
849
849
  return ok(node, "launch");
850
850
  },
851
- async "project.scope"(project2, scope2, id) {
851
+ async "project.scope"(project3, scope2, id) {
852
852
  validateGherkin(scope2);
853
- const node = await rt.create(await resolve(project2), scope, scope2, id);
853
+ const node = await rt.create(await resolve(project3), scope, scope2, id);
854
854
  return ok(node, "scope");
855
855
  },
856
- async "project.milestone"(project2, milestone2, id) {
856
+ async "project.milestone"(project3, milestone2, id) {
857
857
  validateGherkin(milestone2);
858
- const node = await rt.create(await resolve(project2), milestone, milestone2, id);
858
+ const node = await rt.create(await resolve(project3), milestone, milestone2, id);
859
859
  return ok(node, "milestone");
860
860
  },
861
861
  async "project.achieve"(milestone2) {
@@ -863,44 +863,44 @@ ${text}`;
863
863
  await rt.tag(node, "done");
864
864
  return ok(node, "achieve");
865
865
  },
866
- async "project.enroll"(project2, individual2) {
867
- const projNode = await resolve(project2);
866
+ async "project.enroll"(project3, individual2) {
867
+ const projNode = await resolve(project3);
868
868
  await rt.link(projNode, await resolve(individual2), "participation", "participate");
869
869
  return ok(projNode, "enroll");
870
870
  },
871
- async "project.remove"(project2, individual2) {
872
- const projNode = await resolve(project2);
871
+ async "project.remove"(project3, individual2) {
872
+ const projNode = await resolve(project3);
873
873
  await rt.unlink(projNode, await resolve(individual2), "participation", "participate");
874
874
  return ok(projNode, "remove");
875
875
  },
876
- async "project.deliver"(project2, deliverable2, id) {
876
+ async "project.deliver"(project3, deliverable2, id) {
877
877
  validateGherkin(deliverable2);
878
- const node = await rt.create(await resolve(project2), deliverable, deliverable2, id);
878
+ const node = await rt.create(await resolve(project3), deliverable, deliverable2, id);
879
879
  return ok(node, "deliver");
880
880
  },
881
- async "project.wiki"(project2, wiki2, id) {
881
+ async "project.wiki"(project3, wiki2, id) {
882
882
  validateGherkin(wiki2);
883
- const node = await rt.create(await resolve(project2), wiki, wiki2, id);
883
+ const node = await rt.create(await resolve(project3), wiki, wiki2, id);
884
884
  return ok(node, "wiki");
885
885
  },
886
- async "project.archive"(project2) {
887
- return archive2(await resolve(project2), "archive");
886
+ async "project.archive"(project3) {
887
+ return archive2(await resolve(project3), "archive");
888
888
  },
889
- async "project.produce"(project2, content, id, alias) {
889
+ async "project.produce"(project3, content, id, alias) {
890
890
  validateGherkin(content);
891
- const projNode = await resolve(project2);
891
+ const projNode = await resolve(project3);
892
892
  const node = await rt.create(society2, product, content, id, alias);
893
893
  await rt.link(projNode, node, "production", "produce");
894
894
  await rt.link(node, projNode, "origin", "produced-by");
895
895
  return ok(node, "produce");
896
896
  },
897
- async "project.maintain"(project2, individual2) {
898
- const projNode = await resolve(project2);
897
+ async "project.maintain"(project3, individual2) {
898
+ const projNode = await resolve(project3);
899
899
  await rt.link(projNode, await resolve(individual2), "maintain", "maintained-by");
900
900
  return ok(projNode, "maintain");
901
901
  },
902
- async "project.unmaintain"(project2, individual2) {
903
- const projNode = await resolve(project2);
902
+ async "project.unmaintain"(project3, individual2) {
903
+ const projNode = await resolve(project3);
904
904
  await rt.unlink(projNode, await resolve(individual2), "maintain", "maintained-by");
905
905
  return ok(projNode, "unmaintain");
906
906
  },
@@ -1019,7 +1019,7 @@ ${text}`;
1019
1019
  // ---- Census ----
1020
1020
  async "census.list"(type) {
1021
1021
  const target = type === "past" ? past2 : society2;
1022
- const state = await rt.project(target);
1022
+ const state = await project2(target);
1023
1023
  const children = state.children ?? [];
1024
1024
  const filtered = type === "past" ? children : children.filter((c) => type ? c.name === type : c.name !== "past");
1025
1025
  return { state: { ...state, children: filtered }, process: "list" };
@@ -2832,6 +2832,14 @@ var sovereignPermissions = [
2832
2832
  ];
2833
2833
 
2834
2834
  // src/projection.ts
2835
+ var DEFAULT_DEPTH = 1;
2836
+ function createProjection(rt, permissions) {
2837
+ return async (node, ctx) => {
2838
+ const raw = await rt.project(node);
2839
+ const compacted = compactState(raw, ctx?.depth ?? DEFAULT_DEPTH);
2840
+ return permissions.enrich(compacted);
2841
+ };
2842
+ }
2835
2843
  var compactRelations = /* @__PURE__ */ new Set([
2836
2844
  "crowned",
2837
2845
  "belong",
@@ -2844,8 +2852,8 @@ function compact(state) {
2844
2852
  const { children, links, ...node } = state;
2845
2853
  return node;
2846
2854
  }
2847
- function compactState(state) {
2848
- const children = state.children?.map((c) => compactState(c));
2855
+ function compactState(state, depth) {
2856
+ const children = depth > 0 ? state.children?.map((c) => compactState(c, depth - 1)) : state.children?.map((c) => compact(c));
2849
2857
  const compactedLinks = state.links?.map(
2850
2858
  (l) => compactRelations.has(l.relation) ? { ...l, target: compact(l.target) } : { ...l, target: compactLinkedTarget(l.target) }
2851
2859
  );
@@ -2867,6 +2875,7 @@ function compactLinkedTarget(state) {
2867
2875
  var RoleXService = class _RoleXService {
2868
2876
  rt;
2869
2877
  commands;
2878
+ project;
2870
2879
  resourcex;
2871
2880
  issuex;
2872
2881
  repo;
@@ -2901,11 +2910,10 @@ var RoleXService = class _RoleXService {
2901
2910
  return service;
2902
2911
  }
2903
2912
  async init() {
2904
- const originalProject = this.rt.project.bind(this.rt);
2905
- this.rt.project = async (node) => this.permissions.enrich(compactState(await originalProject(node)));
2913
+ this.project = createProjection(this.rt, this.permissions);
2906
2914
  const roots = await this.rt.roots();
2907
2915
  this.society = roots.find((r) => r.name === "society") ?? await this.rt.create(null, society);
2908
- const societyState = await this.rt.project(this.society);
2916
+ const societyState = await this.project(this.society);
2909
2917
  const existingPast = societyState.children?.find((c) => c.name === "past");
2910
2918
  this.past = existingPast ?? await this.rt.create(this.society, past);
2911
2919
  this.commands = createCommands({
@@ -2918,6 +2926,7 @@ var RoleXService = class _RoleXService {
2918
2926
  return node;
2919
2927
  },
2920
2928
  find: (id) => this.find(id),
2929
+ project: this.project,
2921
2930
  resourcex: this.resourcex,
2922
2931
  issuex: this.issuex,
2923
2932
  prototype: this.repo.prototype,
@@ -2939,13 +2948,13 @@ var RoleXService = class _RoleXService {
2939
2948
  const cached = this.roles.get(individual2);
2940
2949
  if (cached) {
2941
2950
  const node2 = await this.findOrAutoBorn(individual2);
2942
- const state2 = await this.rt.project(node2);
2951
+ const state2 = await this.project(node2);
2943
2952
  cached.hydrate(state2);
2944
2953
  await this.restoreSnapshot(cached);
2945
2954
  return cached;
2946
2955
  }
2947
2956
  const node = await this.findOrAutoBorn(individual2);
2948
- const state = await this.rt.project(node);
2957
+ const state = await this.project(node);
2949
2958
  const role = new Role(individual2, {
2950
2959
  commands: this.commands,
2951
2960
  renderer: this.renderer,
@@ -2995,7 +3004,9 @@ var RoleXService = class _RoleXService {
2995
3004
  // inspect — project any node's subtree
2996
3005
  // ================================================================
2997
3006
  async inspect(id) {
2998
- const state = await this.projectById(id);
3007
+ const node = await this.find(id);
3008
+ if (!node) throw new Error(`"${id}" not found.`);
3009
+ const state = await this.project(node);
2999
3010
  const result = { state, process: "inspect" };
3000
3011
  return this.renderer.render("inspect", result);
3001
3012
  }
@@ -3004,7 +3015,7 @@ var RoleXService = class _RoleXService {
3004
3015
  // ================================================================
3005
3016
  async survey(type) {
3006
3017
  const target = type === "past" ? this.past : this.society;
3007
- const state = await this.rt.project(target);
3018
+ const state = await this.project(target);
3008
3019
  const children = state.children ?? [];
3009
3020
  const filtered = type === "past" ? children : children.filter((c) => type ? c.name === type : c.name !== "past");
3010
3021
  const result = { state: { ...state, children: filtered }, process: "list" };
@@ -3040,16 +3051,10 @@ You may be guessing the command name. Load the relevant skill first with skill(l
3040
3051
  // ================================================================
3041
3052
  // Internal helpers
3042
3053
  // ================================================================
3043
- /** Find a node by id across the entire society tree. */
3054
+ /** Find a node by id across the entire society tree (raw, no pipeline). */
3044
3055
  async find(id) {
3045
- const state = await this.rt.project(this.society);
3046
- return findInState(state, id);
3047
- }
3048
- /** Find and project a node's full subtree by id. */
3049
- async projectById(id) {
3050
- const node = await this.find(id);
3051
- if (!node) throw new Error(`"${id}" not found.`);
3052
- return this.rt.project(node);
3056
+ const raw = await this.rt.project(this.society);
3057
+ return findInState(raw, id);
3053
3058
  }
3054
3059
  };
3055
3060
  function isCommandResult(value) {