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

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,30 @@ 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
+ * - All link targets: compact (name/id/tag only, no subtree)
183
+ */
184
+
185
+ interface ProjectionContext {
186
+ /** Children expansion depth. Default 1: one level fully expanded, then compact. */
187
+ depth?: number;
188
+ }
189
+ interface Projection {
190
+ /** Project a node through the full pipeline: raw → compact → enrich. */
191
+ (node: Structure, ctx?: ProjectionContext): Promise<State>;
192
+ }
193
+
170
194
  /**
171
195
  * Commands — platform-agnostic command implementations.
172
196
  *
@@ -188,6 +212,7 @@ interface CommandContext {
188
212
  past: Structure;
189
213
  resolve(id: string): Structure | Promise<Structure>;
190
214
  find(id: string): (Structure | null) | Promise<Structure | null>;
215
+ project: Projection;
191
216
  resourcex?: ResourceX;
192
217
  issuex?: IssueX;
193
218
  prototype?: PrototypeRepository;
@@ -414,6 +439,7 @@ interface RoleX {
414
439
  declare class RoleXService implements RoleX {
415
440
  private rt;
416
441
  private commands;
442
+ private project;
417
443
  private resourcex?;
418
444
  private issuex?;
419
445
  private repo;
@@ -438,10 +464,8 @@ declare class RoleXService implements RoleX {
438
464
  direct<T = unknown>(locator: string, args?: Record<string, unknown>, options?: {
439
465
  raw?: boolean;
440
466
  }): Promise<T>;
441
- /** Find a node by id across the entire society tree. */
467
+ /** Find a node by id across the entire society tree (raw, no pipeline). */
442
468
  private find;
443
- /** Find and project a node's full subtree by id. */
444
- private projectById;
445
469
  }
446
470
 
447
471
  /**
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,41 +2832,36 @@ var sovereignPermissions = [
2832
2832
  ];
2833
2833
 
2834
2834
  // src/projection.ts
2835
- var compactRelations = /* @__PURE__ */ new Set([
2836
- "crowned",
2837
- "belong",
2838
- "appointment",
2839
- "administer",
2840
- "maintained-by",
2841
- "own"
2842
- ]);
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
+ }
2843
2843
  function compact(state) {
2844
2844
  const { children, links, ...node } = state;
2845
2845
  return node;
2846
2846
  }
2847
- function compactState(state) {
2848
- const children = state.children?.map((c) => compactState(c));
2849
- const compactedLinks = state.links?.map(
2850
- (l) => compactRelations.has(l.relation) ? { ...l, target: compact(l.target) } : { ...l, target: compactLinkedTarget(l.target) }
2851
- );
2847
+ function compactState(state, depth) {
2848
+ const children = depth > 0 ? state.children?.map((c) => compactState(c, depth - 1)) : state.children?.map((c) => compact(c));
2849
+ const compactedLinks = state.links?.map((l) => ({
2850
+ ...l,
2851
+ target: compact(l.target)
2852
+ }));
2852
2853
  return {
2853
2854
  ...state,
2854
2855
  ...children ? { children } : {},
2855
2856
  ...compactedLinks ? { links: compactedLinks } : {}
2856
2857
  };
2857
2858
  }
2858
- function compactLinkedTarget(state) {
2859
- const children = state.children?.map((c) => compactLinkedTarget(c));
2860
- return {
2861
- ...state,
2862
- ...children ? { children } : {}
2863
- };
2864
- }
2865
2859
 
2866
2860
  // src/rolex-service.ts
2867
2861
  var RoleXService = class _RoleXService {
2868
2862
  rt;
2869
2863
  commands;
2864
+ project;
2870
2865
  resourcex;
2871
2866
  issuex;
2872
2867
  repo;
@@ -2901,11 +2896,10 @@ var RoleXService = class _RoleXService {
2901
2896
  return service;
2902
2897
  }
2903
2898
  async init() {
2904
- const originalProject = this.rt.project.bind(this.rt);
2905
- this.rt.project = async (node) => this.permissions.enrich(compactState(await originalProject(node)));
2899
+ this.project = createProjection(this.rt, this.permissions);
2906
2900
  const roots = await this.rt.roots();
2907
2901
  this.society = roots.find((r) => r.name === "society") ?? await this.rt.create(null, society);
2908
- const societyState = await this.rt.project(this.society);
2902
+ const societyState = await this.project(this.society);
2909
2903
  const existingPast = societyState.children?.find((c) => c.name === "past");
2910
2904
  this.past = existingPast ?? await this.rt.create(this.society, past);
2911
2905
  this.commands = createCommands({
@@ -2918,6 +2912,7 @@ var RoleXService = class _RoleXService {
2918
2912
  return node;
2919
2913
  },
2920
2914
  find: (id) => this.find(id),
2915
+ project: this.project,
2921
2916
  resourcex: this.resourcex,
2922
2917
  issuex: this.issuex,
2923
2918
  prototype: this.repo.prototype,
@@ -2939,13 +2934,13 @@ var RoleXService = class _RoleXService {
2939
2934
  const cached = this.roles.get(individual2);
2940
2935
  if (cached) {
2941
2936
  const node2 = await this.findOrAutoBorn(individual2);
2942
- const state2 = await this.rt.project(node2);
2937
+ const state2 = await this.project(node2);
2943
2938
  cached.hydrate(state2);
2944
2939
  await this.restoreSnapshot(cached);
2945
2940
  return cached;
2946
2941
  }
2947
2942
  const node = await this.findOrAutoBorn(individual2);
2948
- const state = await this.rt.project(node);
2943
+ const state = await this.project(node);
2949
2944
  const role = new Role(individual2, {
2950
2945
  commands: this.commands,
2951
2946
  renderer: this.renderer,
@@ -2995,7 +2990,9 @@ var RoleXService = class _RoleXService {
2995
2990
  // inspect — project any node's subtree
2996
2991
  // ================================================================
2997
2992
  async inspect(id) {
2998
- const state = await this.projectById(id);
2993
+ const node = await this.find(id);
2994
+ if (!node) throw new Error(`"${id}" not found.`);
2995
+ const state = await this.project(node);
2999
2996
  const result = { state, process: "inspect" };
3000
2997
  return this.renderer.render("inspect", result);
3001
2998
  }
@@ -3004,7 +3001,7 @@ var RoleXService = class _RoleXService {
3004
3001
  // ================================================================
3005
3002
  async survey(type) {
3006
3003
  const target = type === "past" ? this.past : this.society;
3007
- const state = await this.rt.project(target);
3004
+ const state = await this.project(target);
3008
3005
  const children = state.children ?? [];
3009
3006
  const filtered = type === "past" ? children : children.filter((c) => type ? c.name === type : c.name !== "past");
3010
3007
  const result = { state: { ...state, children: filtered }, process: "list" };
@@ -3040,16 +3037,10 @@ You may be guessing the command name. Load the relevant skill first with skill(l
3040
3037
  // ================================================================
3041
3038
  // Internal helpers
3042
3039
  // ================================================================
3043
- /** Find a node by id across the entire society tree. */
3040
+ /** Find a node by id across the entire society tree (raw, no pipeline). */
3044
3041
  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);
3042
+ const raw = await this.rt.project(this.society);
3043
+ return findInState(raw, id);
3053
3044
  }
3054
3045
  };
3055
3046
  function isCommandResult(value) {