@rolexjs/local-platform 1.5.0-dev-20260317075835 → 1.5.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/dist/index.d.ts CHANGED
@@ -14,8 +14,6 @@ import { CommonXDatabase } from '@deepracticex/drizzle';
14
14
  interface LocalPlatformConfig {
15
15
  /** Directory for persistent storage. Defaults to ~/.deepractice/rolex. Set to null for in-memory only. */
16
16
  dataDir?: string | null;
17
- /** Directory for ResourceX storage. Defaults to ~/.deepractice/resourcex. Set to null to disable. */
18
- resourceDir?: string | null;
19
17
  }
20
18
  /** Create a local Platform. Persistent by default ($DEEPRACTICE_HOME/rolex), in-memory if dataDir is null. */
21
19
  declare function localPlatform(config?: LocalPlatformConfig): Platform;
@@ -43,7 +41,7 @@ declare function localPlatform(config?: LocalPlatformConfig): Platform;
43
41
  interface ManifestNode {
44
42
  readonly type: string;
45
43
  readonly ref?: string;
46
- readonly tag?: string;
44
+ readonly tags?: readonly string[];
47
45
  readonly children?: Record<string, ManifestNode>;
48
46
  readonly links?: Record<string, string[]>;
49
47
  }
package/dist/index.js CHANGED
@@ -4,8 +4,6 @@ import { homedir } from "os";
4
4
  import { join as join2 } from "path";
5
5
  import { drizzle } from "@deepracticex/drizzle";
6
6
  import { openDatabase } from "@deepracticex/sqlite";
7
- import { NodeProvider as IssueXNodeProvider } from "@issuexjs/node";
8
- import { NodeProvider } from "@resourcexjs/node-provider";
9
7
 
10
8
  // src/SqliteRepository.ts
11
9
  import { join } from "path";
@@ -88,7 +86,7 @@ function toStructure(row) {
88
86
  parent: null,
89
87
  // Runtime doesn't use parent as Structure; tree is via parentRef
90
88
  ...row.information ? { information: row.information } : {},
91
- ...row.tag ? { tag: row.tag } : {}
89
+ ...row.tag ? { tags: JSON.parse(row.tag) } : {}
92
90
  };
93
91
  }
94
92
  function projectLinked(db, ref) {
@@ -204,11 +202,23 @@ function createSqliteRuntime(db) {
204
202
  and(eq(links.fromRef, to.ref), eq(links.toRef, from.ref), eq(links.relation, reverseName))
205
203
  ).run();
206
204
  },
207
- async tag(node, tagValue) {
205
+ async addTag(node, tag) {
208
206
  if (!node.ref) throw new Error("Node has no ref");
209
207
  const row = db.select().from(nodes).where(eq(nodes.ref, node.ref)).get();
210
208
  if (!row) throw new Error(`Node not found: ${node.ref}`);
211
- db.update(nodes).set({ tag: tagValue }).where(eq(nodes.ref, node.ref)).run();
209
+ const current = row.tag ? JSON.parse(row.tag) : [];
210
+ if (!current.includes(tag)) {
211
+ current.push(tag);
212
+ db.update(nodes).set({ tag: JSON.stringify(current) }).where(eq(nodes.ref, node.ref)).run();
213
+ }
214
+ },
215
+ async removeTag(node, tag) {
216
+ if (!node.ref) throw new Error("Node has no ref");
217
+ const row = db.select().from(nodes).where(eq(nodes.ref, node.ref)).get();
218
+ if (!row) throw new Error(`Node not found: ${node.ref}`);
219
+ const current = row.tag ? JSON.parse(row.tag) : [];
220
+ const filtered = current.filter((t) => t !== tag);
221
+ db.update(nodes).set({ tag: filtered.length > 0 ? JSON.stringify(filtered) : null }).where(eq(nodes.ref, node.ref)).run();
212
222
  },
213
223
  async project(node) {
214
224
  if (!node.ref) throw new Error(`Node has no ref`);
@@ -314,28 +324,12 @@ function localPlatform(config = {}) {
314
324
  const rawDb = openDatabase(dbPath);
315
325
  const db = drizzle(rawDb);
316
326
  const repository = new SqliteRepository(db);
317
- const resourcexProvider = config.resourceDir !== null ? new NodeProvider() : void 0;
318
- const issuexProvider = new IssueXNodeProvider({
319
- db: {
320
- run(sql2, ...params) {
321
- rawDb.prepare(sql2).run(...params);
322
- },
323
- get(sql2, ...params) {
324
- return rawDb.prepare(sql2).get(...params);
325
- },
326
- all(sql2, ...params) {
327
- return rawDb.prepare(sql2).all(...params);
328
- }
329
- }
330
- });
331
327
  const initializer = {
332
328
  async bootstrap() {
333
329
  }
334
330
  };
335
331
  return {
336
332
  repository,
337
- resourcexProvider,
338
- issuexProvider,
339
333
  initializer
340
334
  };
341
335
  }
@@ -363,7 +357,7 @@ function stateToFiles(state) {
363
357
  const entry = {
364
358
  type: node.name,
365
359
  ...node.ref ? { ref: node.ref } : {},
366
- ...node.tag ? { tag: node.tag } : {},
360
+ ...node.tags?.length ? { tags: node.tags } : {},
367
361
  ...node.links && node.links.length > 0 ? { links: buildManifestLinks(node.links) } : {}
368
362
  };
369
363
  if (node.children && node.children.length > 0) {
@@ -427,7 +421,7 @@ function filesToState(manifest, fileContents) {
427
421
  name: node.type,
428
422
  description: "",
429
423
  parent: null,
430
- ...node.tag ? { tag: node.tag } : {},
424
+ ...node.tags?.length ? { tags: node.tags } : {},
431
425
  ...information ? { information } : {},
432
426
  ...children2.length > 0 ? { children: children2 } : {},
433
427
  ...nodeLinks.length > 0 ? { links: nodeLinks } : {}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/LocalPlatform.ts","../src/SqliteRepository.ts","../src/sqliteRuntime.ts","../src/schema.ts","../src/manifest.ts"],"sourcesContent":["/**\n * localPlatform — create a Platform backed by SQLite + local filesystem.\n *\n * Storage:\n * {dataDir}/rolex.db — SQLite database (all state: nodes, links, prototypes, contexts)\n *\n * When dataDir is null, runs with in-memory SQLite (useful for tests).\n */\n\nimport { mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { drizzle } from \"@deepracticex/drizzle\";\nimport { openDatabase } from \"@deepracticex/sqlite\";\nimport { NodeProvider as IssueXNodeProvider } from \"@issuexjs/node\";\nimport { NodeProvider } from \"@resourcexjs/node-provider\";\nimport type { Platform } from \"@rolexjs/core\";\nimport type { Initializer } from \"@rolexjs/system\";\nimport { SqliteRepository } from \"./SqliteRepository.js\";\n\n// ===== Config =====\n\nexport interface LocalPlatformConfig {\n /** Directory for persistent storage. Defaults to ~/.deepractice/rolex. Set to null for in-memory only. */\n dataDir?: string | null;\n /** Directory for ResourceX storage. Defaults to ~/.deepractice/resourcex. Set to null to disable. */\n resourceDir?: string | null;\n}\n\n// ===== Factory =====\n\n/** Resolve the DEEPRACTICE_HOME base directory. Env > default (~/.deepractice). */\nfunction deepracticeHome(): string {\n return process.env.DEEPRACTICE_HOME ?? join(homedir(), \".deepractice\");\n}\n\n/** Create a local Platform. Persistent by default ($DEEPRACTICE_HOME/rolex), in-memory if dataDir is null. */\nexport function localPlatform(config: LocalPlatformConfig = {}): Platform {\n const dataDir =\n config.dataDir === null ? undefined : (config.dataDir ?? join(deepracticeHome(), \"rolex\"));\n\n // ===== SQLite database =====\n\n let dbPath: string;\n if (dataDir) {\n mkdirSync(dataDir, { recursive: true });\n dbPath = join(dataDir, \"rolex.db\");\n } else {\n dbPath = \":memory:\";\n }\n\n const rawDb = openDatabase(dbPath);\n const db = drizzle(rawDb);\n\n // ===== Repository (all state in one place) =====\n\n const repository = new SqliteRepository(db);\n\n // ===== ResourceX Provider =====\n\n const resourcexProvider = config.resourceDir !== null ? new NodeProvider() : undefined;\n\n // ===== IssueX Provider =====\n\n const issuexProvider = new IssueXNodeProvider({\n db: {\n run(sql: string, ...params: unknown[]) {\n rawDb.prepare(sql).run(...params);\n },\n get<T = unknown>(sql: string, ...params: unknown[]): T | null {\n return rawDb.prepare(sql).get(...params) as T | null;\n },\n all<T = unknown>(sql: string, ...params: unknown[]): T[] {\n return rawDb.prepare(sql).all(...params) as T[];\n },\n },\n });\n\n // ===== Initializer =====\n\n const initializer: Initializer = {\n async bootstrap() {},\n };\n\n return {\n repository,\n resourcexProvider,\n issuexProvider,\n initializer,\n };\n}\n","/**\n * SqliteRepository — RoleXRepository backed by SQLite via Drizzle.\n *\n * Five tables: nodes, links, prototypes, contexts, prototype_migrations.\n * Schema managed by Drizzle ORM migrations.\n */\n\nimport { join } from \"node:path\";\nimport type { CommonXDatabase } from \"@deepracticex/drizzle\";\nimport { migrate } from \"@deepracticex/drizzle\";\nimport type {\n ContextData,\n MigrationRecord,\n PrototypeRepository,\n RoleXRepository,\n} from \"@rolexjs/core\";\nimport type { Runtime } from \"@rolexjs/system\";\nimport { sql } from \"drizzle-orm\";\nimport { createSqliteRuntime } from \"./sqliteRuntime.js\";\n\ntype DB = CommonXDatabase;\n\n// ===== Repository =====\n\nexport class SqliteRepository implements RoleXRepository {\n readonly runtime: Runtime;\n readonly prototype: PrototypeRepository;\n\n constructor(private db: DB) {\n // Run Drizzle migrations — handles schema creation and evolution\n migrate(db, {\n migrationsFolder: join(import.meta.dirname, \"../drizzle\"),\n });\n\n this.runtime = createSqliteRuntime(db);\n this.prototype = createPrototypeRepository(db);\n }\n\n async saveContext(roleId: string, data: ContextData): Promise<void> {\n this.db.run(\n sql`INSERT OR REPLACE INTO contexts (role_id, focused_goal_id, focused_plan_id)\n VALUES (${roleId}, ${data.focusedGoalId}, ${data.focusedPlanId})`\n );\n }\n\n async loadContext(roleId: string): Promise<ContextData | null> {\n const row = this.db.all<{\n role_id: string;\n focused_goal_id: string | null;\n focused_plan_id: string | null;\n }>(\n sql`SELECT role_id, focused_goal_id, focused_plan_id FROM contexts WHERE role_id = ${roleId}`\n );\n if (row.length === 0) return null;\n return {\n focusedGoalId: row[0].focused_goal_id,\n focusedPlanId: row[0].focused_plan_id,\n };\n }\n}\n\n// ===== Prototype Registry (SQLite-backed) =====\n\nfunction createPrototypeRepository(db: DB): PrototypeRepository {\n return {\n async settle(id: string, source: string) {\n db.run(sql`INSERT OR REPLACE INTO prototypes (id, source) VALUES (${id}, ${source})`);\n },\n\n async evict(id: string) {\n db.run(sql`DELETE FROM prototypes WHERE id = ${id}`);\n db.run(sql`DELETE FROM prototype_migrations WHERE prototype_id = ${id}`);\n },\n\n async list(): Promise<Record<string, string>> {\n const rows = db.all<{ id: string; source: string }>(sql`SELECT id, source FROM prototypes`);\n const result: Record<string, string> = {};\n for (const row of rows) {\n result[row.id] = row.source;\n }\n return result;\n },\n\n async recordMigration(\n prototypeId: string,\n migrationId: string,\n version: number,\n checksum: string\n ) {\n const executedAt = new Date().toISOString();\n db.run(\n sql`INSERT OR REPLACE INTO prototype_migrations (prototype_id, migration_id, version, checksum, executed_at)\n VALUES (${prototypeId}, ${migrationId}, ${version}, ${checksum}, ${executedAt})`\n );\n },\n\n async getMigrationHistory(prototypeId: string): Promise<MigrationRecord[]> {\n return db\n .all<{\n prototype_id: string;\n migration_id: string;\n version: number;\n checksum: string;\n executed_at: string;\n }>(\n sql`SELECT prototype_id, migration_id, version, checksum, executed_at\n FROM prototype_migrations\n WHERE prototype_id = ${prototypeId}\n ORDER BY version`\n )\n .map((row) => ({\n prototypeId: row.prototype_id,\n migrationId: row.migration_id,\n version: row.version,\n checksum: row.checksum,\n executedAt: row.executed_at,\n }));\n },\n\n async hasMigration(prototypeId: string, migrationId: string): Promise<boolean> {\n const rows = db.all<{ cnt: number }>(\n sql`SELECT COUNT(*) as cnt FROM prototype_migrations\n WHERE prototype_id = ${prototypeId} AND migration_id = ${migrationId}`\n );\n return rows.length > 0 && rows[0].cnt > 0;\n },\n };\n}\n","/**\n * SQLite-backed Runtime — single source of truth.\n *\n * Every operation reads/writes directly to SQLite.\n * No in-memory Map, no load/save cycle, no stale refs.\n */\n\nimport type { CommonXDatabase } from \"@deepracticex/drizzle\";\nimport type { Runtime, State, Structure } from \"@rolexjs/system\";\nimport { and, eq, isNull } from \"drizzle-orm\";\nimport { links, nodes } from \"./schema.js\";\n\ntype DB = CommonXDatabase;\n\n// ===== Helpers =====\n\nfunction nextRef(db: DB): string {\n const max = db\n .select({ ref: nodes.ref })\n .from(nodes)\n .all()\n .reduce((max, r) => {\n const n = parseInt(r.ref.slice(1), 10);\n return Number.isNaN(n) ? max : Math.max(max, n);\n }, 0);\n return `n${max + 1}`;\n}\n\nfunction toStructure(row: typeof nodes.$inferSelect): Structure {\n return {\n ref: row.ref,\n ...(row.id ? { id: row.id } : {}),\n ...(row.alias ? { alias: JSON.parse(row.alias) } : {}),\n name: row.name,\n description: row.description ?? \"\",\n parent: null, // Runtime doesn't use parent as Structure; tree is via parentRef\n ...(row.information ? { information: row.information } : {}),\n ...(row.tag ? { tag: row.tag } : {}),\n };\n}\n\n// ===== Projection =====\n\n/** Project a linked node with full subtree (no further link-following to prevent cycles). */\nfunction projectLinked(db: DB, ref: string): State {\n const row = db.select().from(nodes).where(eq(nodes.ref, ref)).get();\n if (!row) throw new Error(`Node not found: ${ref}`);\n const children = db.select().from(nodes).where(eq(nodes.parentRef, ref)).all();\n return {\n ...toStructure(row),\n children: children.map((c) => projectLinked(db, c.ref)),\n };\n}\n\n/** Project a node with full subtree and links (top-level only). */\nfunction projectNode(db: DB, ref: string): State {\n const row = db.select().from(nodes).where(eq(nodes.ref, ref)).get();\n if (!row) throw new Error(`Node not found: ${ref}`);\n\n const children = db.select().from(nodes).where(eq(nodes.parentRef, ref)).all();\n const nodeLinks = db.select().from(links).where(eq(links.fromRef, ref)).all();\n\n return {\n ...toStructure(row),\n children: children.map((c) => projectNode(db, c.ref)),\n ...(nodeLinks.length > 0\n ? {\n links: nodeLinks.map((l) => ({\n relation: l.relation,\n target: projectLinked(db, l.toRef),\n })),\n }\n : {}),\n };\n}\n\n// ===== Subtree removal =====\n\nfunction removeSubtree(db: DB, ref: string): void {\n // Remove children first (depth-first)\n const children = db.select({ ref: nodes.ref }).from(nodes).where(eq(nodes.parentRef, ref)).all();\n for (const child of children) {\n removeSubtree(db, child.ref);\n }\n\n // Remove links from/to this node\n db.delete(links).where(eq(links.fromRef, ref)).run();\n db.delete(links).where(eq(links.toRef, ref)).run();\n\n // Remove the node itself\n db.delete(nodes).where(eq(nodes.ref, ref)).run();\n}\n\n// ===== Runtime factory =====\n\nexport function createSqliteRuntime(db: DB): Runtime {\n return {\n async create(parent, type, information, id, alias) {\n // Idempotent: same id under same parent → return existing.\n if (id) {\n const existing = db\n .select()\n .from(nodes)\n .where(and(eq(nodes.id, id), eq(nodes.parentRef, parent?.ref ?? null)))\n .get();\n if (existing) return toStructure(existing);\n }\n const ref = nextRef(db);\n db.insert(nodes)\n .values({\n ref,\n id: id ?? null,\n alias: alias && alias.length > 0 ? JSON.stringify(alias) : null,\n name: type.name,\n description: type.description,\n parentRef: parent?.ref ?? null,\n information: information ?? null,\n tag: null,\n })\n .run();\n return toStructure(db.select().from(nodes).where(eq(nodes.ref, ref)).get()!);\n },\n\n async remove(node) {\n if (!node.ref) return;\n const row = db.select().from(nodes).where(eq(nodes.ref, node.ref)).get();\n if (!row) return;\n\n // Detach from parent's children (implicit via parentRef)\n removeSubtree(db, node.ref);\n },\n\n async transform(source, target, information) {\n if (!source.ref) throw new Error(\"Source node has no ref\");\n const row = db.select().from(nodes).where(eq(nodes.ref, source.ref)).get();\n if (!row) throw new Error(`Source node not found: ${source.ref}`);\n\n const targetParent = target.parent;\n if (!targetParent) {\n throw new Error(`Cannot transform to root structure: ${target.name}`);\n }\n\n const parentRow = db.select().from(nodes).where(eq(nodes.name, targetParent.name)).get();\n if (!parentRow) {\n throw new Error(`No node found for structure: ${targetParent.name}`);\n }\n\n // Reparent + update type in place — subtree preserved\n db.update(nodes)\n .set({\n parentRef: parentRow.ref,\n name: target.name,\n description: target.description,\n ...(information !== undefined ? { information } : {}),\n })\n .where(eq(nodes.ref, source.ref))\n .run();\n\n return toStructure(db.select().from(nodes).where(eq(nodes.ref, source.ref)).get()!);\n },\n\n async link(from, to, relationName, reverseName) {\n if (!from.ref) throw new Error(\"Source node has no ref\");\n if (!to.ref) throw new Error(\"Target node has no ref\");\n\n // Forward: from → to\n const existsForward = db\n .select()\n .from(links)\n .where(\n and(\n eq(links.fromRef, from.ref),\n eq(links.toRef, to.ref),\n eq(links.relation, relationName)\n )\n )\n .get();\n if (!existsForward) {\n db.insert(links).values({ fromRef: from.ref, toRef: to.ref, relation: relationName }).run();\n }\n\n // Reverse: to → from\n const existsReverse = db\n .select()\n .from(links)\n .where(\n and(eq(links.fromRef, to.ref), eq(links.toRef, from.ref), eq(links.relation, reverseName))\n )\n .get();\n if (!existsReverse) {\n db.insert(links).values({ fromRef: to.ref, toRef: from.ref, relation: reverseName }).run();\n }\n },\n\n async unlink(from, to, relationName, reverseName) {\n if (!from.ref || !to.ref) return;\n\n db.delete(links)\n .where(\n and(\n eq(links.fromRef, from.ref),\n eq(links.toRef, to.ref),\n eq(links.relation, relationName)\n )\n )\n .run();\n\n db.delete(links)\n .where(\n and(eq(links.fromRef, to.ref), eq(links.toRef, from.ref), eq(links.relation, reverseName))\n )\n .run();\n },\n\n async tag(node, tagValue) {\n if (!node.ref) throw new Error(\"Node has no ref\");\n const row = db.select().from(nodes).where(eq(nodes.ref, node.ref)).get();\n if (!row) throw new Error(`Node not found: ${node.ref}`);\n db.update(nodes).set({ tag: tagValue }).where(eq(nodes.ref, node.ref)).run();\n },\n\n async project(node) {\n if (!node.ref) throw new Error(`Node has no ref`);\n return projectNode(db, node.ref);\n },\n\n async roots() {\n const rows = db.select().from(nodes).where(isNull(nodes.parentRef)).all();\n return rows.map(toStructure);\n },\n };\n}\n","/**\n * Drizzle schema — SQLite tables for RoleX.\n *\n * Five tables:\n * nodes — tree backbone (Structure instances)\n * links — cross-branch relations (bidirectional)\n * prototypes — which prototype packages are settled\n * contexts — per-role session focus state\n * prototype_migrations — Flyway-style migration history\n */\n\nimport { index, integer, primaryKey, sqliteTable, text } from \"drizzle-orm/sqlite-core\";\n\n/**\n * nodes — every node in the society graph.\n *\n * Maps 1:1 to the Structure interface:\n * ref → graph-internal reference (primary key)\n * id → user-facing kebab-case identifier\n * alias → JSON array of alternative names\n * name → structure type (\"individual\", \"goal\", \"task\", etc.)\n * description → what this structure is\n * parent_ref → tree parent (self-referencing foreign key)\n * information → Gherkin Feature source text\n * tag → generic label (\"done\", \"abandoned\")\n */\nexport const nodes = sqliteTable(\n \"nodes\",\n {\n ref: text(\"ref\").primaryKey(),\n id: text(\"id\"),\n alias: text(\"alias\"), // JSON array: '[\"Sean\",\"姜山\"]'\n name: text(\"name\").notNull(),\n description: text(\"description\").default(\"\"),\n parentRef: text(\"parent_ref\").references((): any => nodes.ref),\n information: text(\"information\"),\n tag: text(\"tag\"),\n },\n (table) => [\n index(\"idx_nodes_id\").on(table.id),\n index(\"idx_nodes_name\").on(table.name),\n index(\"idx_nodes_parent_ref\").on(table.parentRef),\n ]\n);\n\n/**\n * links — cross-branch relations between nodes.\n *\n * Bidirectional: if A→B is \"membership\", B→A is \"belong\".\n * Both directions stored as separate rows.\n */\nexport const links = sqliteTable(\n \"links\",\n {\n fromRef: text(\"from_ref\")\n .notNull()\n .references(() => nodes.ref),\n toRef: text(\"to_ref\")\n .notNull()\n .references(() => nodes.ref),\n relation: text(\"relation\").notNull(),\n },\n (table) => [\n primaryKey({ columns: [table.fromRef, table.toRef, table.relation] }),\n index(\"idx_links_from\").on(table.fromRef),\n index(\"idx_links_to\").on(table.toRef),\n ]\n);\n\n/**\n * prototypes — which prototype packages are settled.\n */\nexport const prototypes = sqliteTable(\"prototypes\", {\n id: text(\"id\").primaryKey(),\n source: text(\"source\").notNull(),\n});\n\n/**\n * contexts — per-role session focus state.\n */\nexport const contexts = sqliteTable(\"contexts\", {\n roleId: text(\"role_id\").primaryKey(),\n focusedGoalId: text(\"focused_goal_id\"),\n focusedPlanId: text(\"focused_plan_id\"),\n});\n\n/**\n * prototype_migrations — Flyway-style migration history.\n *\n * Records which migrations have been executed for each prototype.\n */\nexport const prototypeMigrations = sqliteTable(\n \"prototype_migrations\",\n {\n prototypeId: text(\"prototype_id\").notNull(),\n migrationId: text(\"migration_id\").notNull(),\n version: integer(\"version\").notNull(),\n checksum: text(\"checksum\").notNull(),\n executedAt: text(\"executed_at\").notNull(),\n },\n (table) => [primaryKey({ columns: [table.prototypeId, table.migrationId] })]\n);\n","/**\n * Manifest — file-based storage format for RoleX entities.\n *\n * Storage layout:\n * role/<id>/\n * individual.json — manifest (tree structure + links)\n * <id>.<type>.feature — node information (Gherkin)\n *\n * organization/<id>/\n * organization.json — manifest (tree structure + links)\n * <id>.<type>.feature — node information (Gherkin)\n *\n * Rules:\n * - Directories: only role/ and organization/ at top level\n * - Files: all [id].[type].feature, flat within the entity directory\n * - Manifest: tree structure in JSON, content in .feature files\n * - Nodes without explicit id default to their type name\n */\n\nimport type { State } from \"@rolexjs/system\";\n\n// ===== Manifest types =====\n\n/** A node in the manifest tree. */\nexport interface ManifestNode {\n readonly type: string;\n readonly ref?: string;\n readonly tag?: string;\n readonly children?: Record<string, ManifestNode>;\n readonly links?: Record<string, string[]>;\n}\n\n/** Root manifest for an entity (individual or organization). */\nexport interface Manifest {\n readonly id: string;\n readonly type: string;\n readonly ref?: string;\n readonly alias?: readonly string[];\n readonly children?: Record<string, ManifestNode>;\n readonly links?: Record<string, string[]>;\n}\n\n// ===== State → files =====\n\nexport interface FileEntry {\n readonly path: string;\n readonly content: string;\n}\n\n/**\n * Convert a State tree to a manifest + feature files.\n * Returns the manifest and a list of file entries (path → content).\n */\nexport function stateToFiles(state: State): { manifest: Manifest; files: FileEntry[] } {\n const files: FileEntry[] = [];\n\n const collectFiles = (node: State, nodeId: string) => {\n if (node.information) {\n files.push({\n path: `${nodeId}.${node.name}.feature`,\n content: node.information,\n });\n }\n if (node.children) {\n for (const child of node.children) {\n const childId = child.id ?? child.name;\n collectFiles(child, childId);\n }\n }\n };\n\n const rootId = state.id ?? state.name;\n collectFiles(state, rootId);\n\n const buildManifestNode = (node: State): ManifestNode => {\n const entry: ManifestNode = {\n type: node.name,\n ...(node.ref ? { ref: node.ref } : {}),\n ...(node.tag ? { tag: node.tag } : {}),\n ...(node.links && node.links.length > 0 ? { links: buildManifestLinks(node.links) } : {}),\n };\n if (node.children && node.children.length > 0) {\n const children: Record<string, ManifestNode> = {};\n for (const child of node.children) {\n const childId = child.id ?? child.name;\n children[childId] = buildManifestNode(child);\n }\n return { ...entry, children };\n }\n return entry;\n };\n\n const manifestNode = buildManifestNode(state);\n\n const manifest: Manifest = {\n id: rootId,\n type: state.name,\n ...(state.ref ? { ref: state.ref } : {}),\n ...(state.alias ? { alias: state.alias } : {}),\n ...(manifestNode.children ? { children: manifestNode.children } : {}),\n ...(state.links && state.links.length > 0\n ? {\n links: buildManifestLinks(state.links),\n }\n : {}),\n };\n\n return { manifest, files };\n}\n\nfunction buildManifestLinks(\n links: readonly { readonly relation: string; readonly target: State }[]\n): Record<string, string[]> {\n const result: Record<string, string[]> = {};\n for (const link of links) {\n const targetId = link.target.id ?? link.target.name;\n if (!result[link.relation]) {\n result[link.relation] = [];\n }\n result[link.relation].push(targetId);\n }\n return result;\n}\n\n// ===== Files → State =====\n\n/**\n * Convert a manifest + feature file contents to a State tree.\n * fileContents maps filename (e.g. \"role-creation.principle.feature\") to Gherkin text.\n */\nexport function filesToState(manifest: Manifest, fileContents: Record<string, string>): State {\n const buildState = (id: string, node: ManifestNode): State => {\n const filename = `${id}.${node.type}.feature`;\n const information = fileContents[filename];\n\n const children: State[] = [];\n if (node.children) {\n for (const [childId, childNode] of Object.entries(node.children)) {\n children.push(buildState(childId, childNode));\n }\n }\n\n const nodeLinks: { relation: string; target: State }[] = [];\n if (node.links) {\n for (const [relation, targetIds] of Object.entries(node.links)) {\n for (const targetId of targetIds) {\n nodeLinks.push({\n relation,\n target: { id: targetId, name: \"\", description: \"\", parent: null },\n });\n }\n }\n }\n\n return {\n ...(node.ref ? { ref: node.ref } : {}),\n id,\n name: node.type,\n description: \"\",\n parent: null,\n ...(node.tag ? { tag: node.tag } : {}),\n ...(information ? { information } : {}),\n ...(children.length > 0 ? { children } : {}),\n ...(nodeLinks.length > 0 ? { links: nodeLinks } : {}),\n };\n };\n\n const rootFilename = `${manifest.id}.${manifest.type}.feature`;\n const rootInformation = fileContents[rootFilename];\n\n const children: State[] = [];\n if (manifest.children) {\n for (const [childId, childNode] of Object.entries(manifest.children)) {\n children.push(buildState(childId, childNode));\n }\n }\n\n const links: { relation: string; target: State }[] = [];\n if (manifest.links) {\n for (const [relation, targetIds] of Object.entries(manifest.links)) {\n for (const targetId of targetIds) {\n links.push({\n relation,\n target: {\n id: targetId,\n name: \"\",\n description: \"\",\n parent: null,\n },\n });\n }\n }\n }\n\n return {\n ...(manifest.ref ? { ref: manifest.ref } : {}),\n id: manifest.id,\n ...(manifest.alias ? { alias: manifest.alias } : {}),\n name: manifest.type,\n description: \"\",\n parent: null,\n ...(rootInformation ? { information: rootInformation } : {}),\n ...(children.length > 0 ? { children } : {}),\n ...(links.length > 0 ? { links } : {}),\n };\n}\n"],"mappings":"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","names":["join","max","join","sql","links","children"]}
1
+ {"version":3,"sources":["../src/LocalPlatform.ts","../src/SqliteRepository.ts","../src/sqliteRuntime.ts","../src/schema.ts","../src/manifest.ts"],"sourcesContent":["/**\n * localPlatform — create a Platform backed by SQLite + local filesystem.\n *\n * Storage:\n * {dataDir}/rolex.db — SQLite database (all state: nodes, links, prototypes, contexts)\n *\n * When dataDir is null, runs with in-memory SQLite (useful for tests).\n */\n\nimport { mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { drizzle } from \"@deepracticex/drizzle\";\nimport { openDatabase } from \"@deepracticex/sqlite\";\nimport type { Platform } from \"@rolexjs/core\";\nimport type { Initializer } from \"@rolexjs/system\";\nimport { SqliteRepository } from \"./SqliteRepository.js\";\n\n// ===== Config =====\n\nexport interface LocalPlatformConfig {\n /** Directory for persistent storage. Defaults to ~/.deepractice/rolex. Set to null for in-memory only. */\n dataDir?: string | null;\n}\n\n// ===== Factory =====\n\n/** Resolve the DEEPRACTICE_HOME base directory. Env > default (~/.deepractice). */\nfunction deepracticeHome(): string {\n return process.env.DEEPRACTICE_HOME ?? join(homedir(), \".deepractice\");\n}\n\n/** Create a local Platform. Persistent by default ($DEEPRACTICE_HOME/rolex), in-memory if dataDir is null. */\nexport function localPlatform(config: LocalPlatformConfig = {}): Platform {\n const dataDir =\n config.dataDir === null ? undefined : (config.dataDir ?? join(deepracticeHome(), \"rolex\"));\n\n // ===== SQLite database =====\n\n let dbPath: string;\n if (dataDir) {\n mkdirSync(dataDir, { recursive: true });\n dbPath = join(dataDir, \"rolex.db\");\n } else {\n dbPath = \":memory:\";\n }\n\n const rawDb = openDatabase(dbPath);\n const db = drizzle(rawDb);\n\n // ===== Repository (all state in one place) =====\n\n const repository = new SqliteRepository(db);\n\n // ===== Initializer =====\n\n const initializer: Initializer = {\n async bootstrap() {},\n };\n\n return {\n repository,\n initializer,\n };\n}\n","/**\n * SqliteRepository — RoleXRepository backed by SQLite via Drizzle.\n *\n * Five tables: nodes, links, prototypes, contexts, prototype_migrations.\n * Schema managed by Drizzle ORM migrations.\n */\n\nimport { join } from \"node:path\";\nimport type { CommonXDatabase } from \"@deepracticex/drizzle\";\nimport { migrate } from \"@deepracticex/drizzle\";\nimport type {\n ContextData,\n MigrationRecord,\n PrototypeRepository,\n RoleXRepository,\n} from \"@rolexjs/core\";\nimport type { Runtime } from \"@rolexjs/system\";\nimport { sql } from \"drizzle-orm\";\nimport { createSqliteRuntime } from \"./sqliteRuntime.js\";\n\ntype DB = CommonXDatabase;\n\n// ===== Repository =====\n\nexport class SqliteRepository implements RoleXRepository {\n readonly runtime: Runtime;\n readonly prototype: PrototypeRepository;\n\n constructor(private db: DB) {\n // Run Drizzle migrations — handles schema creation and evolution\n migrate(db, {\n migrationsFolder: join(import.meta.dirname, \"../drizzle\"),\n });\n\n this.runtime = createSqliteRuntime(db);\n this.prototype = createPrototypeRepository(db);\n }\n\n async saveContext(roleId: string, data: ContextData): Promise<void> {\n this.db.run(\n sql`INSERT OR REPLACE INTO contexts (role_id, focused_goal_id, focused_plan_id)\n VALUES (${roleId}, ${data.focusedGoalId}, ${data.focusedPlanId})`\n );\n }\n\n async loadContext(roleId: string): Promise<ContextData | null> {\n const row = this.db.all<{\n role_id: string;\n focused_goal_id: string | null;\n focused_plan_id: string | null;\n }>(\n sql`SELECT role_id, focused_goal_id, focused_plan_id FROM contexts WHERE role_id = ${roleId}`\n );\n if (row.length === 0) return null;\n return {\n focusedGoalId: row[0].focused_goal_id,\n focusedPlanId: row[0].focused_plan_id,\n };\n }\n}\n\n// ===== Prototype Registry (SQLite-backed) =====\n\nfunction createPrototypeRepository(db: DB): PrototypeRepository {\n return {\n async settle(id: string, source: string) {\n db.run(sql`INSERT OR REPLACE INTO prototypes (id, source) VALUES (${id}, ${source})`);\n },\n\n async evict(id: string) {\n db.run(sql`DELETE FROM prototypes WHERE id = ${id}`);\n db.run(sql`DELETE FROM prototype_migrations WHERE prototype_id = ${id}`);\n },\n\n async list(): Promise<Record<string, string>> {\n const rows = db.all<{ id: string; source: string }>(sql`SELECT id, source FROM prototypes`);\n const result: Record<string, string> = {};\n for (const row of rows) {\n result[row.id] = row.source;\n }\n return result;\n },\n\n async recordMigration(\n prototypeId: string,\n migrationId: string,\n version: number,\n checksum: string\n ) {\n const executedAt = new Date().toISOString();\n db.run(\n sql`INSERT OR REPLACE INTO prototype_migrations (prototype_id, migration_id, version, checksum, executed_at)\n VALUES (${prototypeId}, ${migrationId}, ${version}, ${checksum}, ${executedAt})`\n );\n },\n\n async getMigrationHistory(prototypeId: string): Promise<MigrationRecord[]> {\n return db\n .all<{\n prototype_id: string;\n migration_id: string;\n version: number;\n checksum: string;\n executed_at: string;\n }>(\n sql`SELECT prototype_id, migration_id, version, checksum, executed_at\n FROM prototype_migrations\n WHERE prototype_id = ${prototypeId}\n ORDER BY version`\n )\n .map((row) => ({\n prototypeId: row.prototype_id,\n migrationId: row.migration_id,\n version: row.version,\n checksum: row.checksum,\n executedAt: row.executed_at,\n }));\n },\n\n async hasMigration(prototypeId: string, migrationId: string): Promise<boolean> {\n const rows = db.all<{ cnt: number }>(\n sql`SELECT COUNT(*) as cnt FROM prototype_migrations\n WHERE prototype_id = ${prototypeId} AND migration_id = ${migrationId}`\n );\n return rows.length > 0 && rows[0].cnt > 0;\n },\n };\n}\n","/**\n * SQLite-backed Runtime — single source of truth.\n *\n * Every operation reads/writes directly to SQLite.\n * No in-memory Map, no load/save cycle, no stale refs.\n */\n\nimport type { CommonXDatabase } from \"@deepracticex/drizzle\";\nimport type { Runtime, State, Structure } from \"@rolexjs/system\";\nimport { and, eq, isNull } from \"drizzle-orm\";\nimport { links, nodes } from \"./schema.js\";\n\ntype DB = CommonXDatabase;\n\n// ===== Helpers =====\n\nfunction nextRef(db: DB): string {\n const max = db\n .select({ ref: nodes.ref })\n .from(nodes)\n .all()\n .reduce((max, r) => {\n const n = parseInt(r.ref.slice(1), 10);\n return Number.isNaN(n) ? max : Math.max(max, n);\n }, 0);\n return `n${max + 1}`;\n}\n\nfunction toStructure(row: typeof nodes.$inferSelect): Structure {\n return {\n ref: row.ref,\n ...(row.id ? { id: row.id } : {}),\n ...(row.alias ? { alias: JSON.parse(row.alias) } : {}),\n name: row.name,\n description: row.description ?? \"\",\n parent: null, // Runtime doesn't use parent as Structure; tree is via parentRef\n ...(row.information ? { information: row.information } : {}),\n ...(row.tag ? { tags: JSON.parse(row.tag) } : {}),\n };\n}\n\n// ===== Projection =====\n\n/** Project a linked node with full subtree (no further link-following to prevent cycles). */\nfunction projectLinked(db: DB, ref: string): State {\n const row = db.select().from(nodes).where(eq(nodes.ref, ref)).get();\n if (!row) throw new Error(`Node not found: ${ref}`);\n const children = db.select().from(nodes).where(eq(nodes.parentRef, ref)).all();\n return {\n ...toStructure(row),\n children: children.map((c) => projectLinked(db, c.ref)),\n };\n}\n\n/** Project a node with full subtree and links (top-level only). */\nfunction projectNode(db: DB, ref: string): State {\n const row = db.select().from(nodes).where(eq(nodes.ref, ref)).get();\n if (!row) throw new Error(`Node not found: ${ref}`);\n\n const children = db.select().from(nodes).where(eq(nodes.parentRef, ref)).all();\n const nodeLinks = db.select().from(links).where(eq(links.fromRef, ref)).all();\n\n return {\n ...toStructure(row),\n children: children.map((c) => projectNode(db, c.ref)),\n ...(nodeLinks.length > 0\n ? {\n links: nodeLinks.map((l) => ({\n relation: l.relation,\n target: projectLinked(db, l.toRef),\n })),\n }\n : {}),\n };\n}\n\n// ===== Subtree removal =====\n\nfunction removeSubtree(db: DB, ref: string): void {\n // Remove children first (depth-first)\n const children = db.select({ ref: nodes.ref }).from(nodes).where(eq(nodes.parentRef, ref)).all();\n for (const child of children) {\n removeSubtree(db, child.ref);\n }\n\n // Remove links from/to this node\n db.delete(links).where(eq(links.fromRef, ref)).run();\n db.delete(links).where(eq(links.toRef, ref)).run();\n\n // Remove the node itself\n db.delete(nodes).where(eq(nodes.ref, ref)).run();\n}\n\n// ===== Runtime factory =====\n\nexport function createSqliteRuntime(db: DB): Runtime {\n return {\n async create(parent, type, information, id, alias) {\n // Idempotent: same id under same parent → return existing.\n if (id) {\n const existing = db\n .select()\n .from(nodes)\n .where(and(eq(nodes.id, id), eq(nodes.parentRef, parent?.ref ?? null)))\n .get();\n if (existing) return toStructure(existing);\n }\n const ref = nextRef(db);\n db.insert(nodes)\n .values({\n ref,\n id: id ?? null,\n alias: alias && alias.length > 0 ? JSON.stringify(alias) : null,\n name: type.name,\n description: type.description,\n parentRef: parent?.ref ?? null,\n information: information ?? null,\n tag: null,\n })\n .run();\n return toStructure(db.select().from(nodes).where(eq(nodes.ref, ref)).get()!);\n },\n\n async remove(node) {\n if (!node.ref) return;\n const row = db.select().from(nodes).where(eq(nodes.ref, node.ref)).get();\n if (!row) return;\n\n // Detach from parent's children (implicit via parentRef)\n removeSubtree(db, node.ref);\n },\n\n async transform(source, target, information) {\n if (!source.ref) throw new Error(\"Source node has no ref\");\n const row = db.select().from(nodes).where(eq(nodes.ref, source.ref)).get();\n if (!row) throw new Error(`Source node not found: ${source.ref}`);\n\n const targetParent = target.parent;\n if (!targetParent) {\n throw new Error(`Cannot transform to root structure: ${target.name}`);\n }\n\n const parentRow = db.select().from(nodes).where(eq(nodes.name, targetParent.name)).get();\n if (!parentRow) {\n throw new Error(`No node found for structure: ${targetParent.name}`);\n }\n\n // Reparent + update type in place — subtree preserved\n db.update(nodes)\n .set({\n parentRef: parentRow.ref,\n name: target.name,\n description: target.description,\n ...(information !== undefined ? { information } : {}),\n })\n .where(eq(nodes.ref, source.ref))\n .run();\n\n return toStructure(db.select().from(nodes).where(eq(nodes.ref, source.ref)).get()!);\n },\n\n async link(from, to, relationName, reverseName) {\n if (!from.ref) throw new Error(\"Source node has no ref\");\n if (!to.ref) throw new Error(\"Target node has no ref\");\n\n // Forward: from → to\n const existsForward = db\n .select()\n .from(links)\n .where(\n and(\n eq(links.fromRef, from.ref),\n eq(links.toRef, to.ref),\n eq(links.relation, relationName)\n )\n )\n .get();\n if (!existsForward) {\n db.insert(links).values({ fromRef: from.ref, toRef: to.ref, relation: relationName }).run();\n }\n\n // Reverse: to → from\n const existsReverse = db\n .select()\n .from(links)\n .where(\n and(eq(links.fromRef, to.ref), eq(links.toRef, from.ref), eq(links.relation, reverseName))\n )\n .get();\n if (!existsReverse) {\n db.insert(links).values({ fromRef: to.ref, toRef: from.ref, relation: reverseName }).run();\n }\n },\n\n async unlink(from, to, relationName, reverseName) {\n if (!from.ref || !to.ref) return;\n\n db.delete(links)\n .where(\n and(\n eq(links.fromRef, from.ref),\n eq(links.toRef, to.ref),\n eq(links.relation, relationName)\n )\n )\n .run();\n\n db.delete(links)\n .where(\n and(eq(links.fromRef, to.ref), eq(links.toRef, from.ref), eq(links.relation, reverseName))\n )\n .run();\n },\n\n async addTag(node, tag) {\n if (!node.ref) throw new Error(\"Node has no ref\");\n const row = db.select().from(nodes).where(eq(nodes.ref, node.ref)).get();\n if (!row) throw new Error(`Node not found: ${node.ref}`);\n const current: string[] = row.tag ? JSON.parse(row.tag) : [];\n if (!current.includes(tag)) {\n current.push(tag);\n db.update(nodes)\n .set({ tag: JSON.stringify(current) })\n .where(eq(nodes.ref, node.ref))\n .run();\n }\n },\n\n async removeTag(node, tag) {\n if (!node.ref) throw new Error(\"Node has no ref\");\n const row = db.select().from(nodes).where(eq(nodes.ref, node.ref)).get();\n if (!row) throw new Error(`Node not found: ${node.ref}`);\n const current: string[] = row.tag ? JSON.parse(row.tag) : [];\n const filtered = current.filter((t) => t !== tag);\n db.update(nodes)\n .set({ tag: filtered.length > 0 ? JSON.stringify(filtered) : null })\n .where(eq(nodes.ref, node.ref))\n .run();\n },\n\n async project(node) {\n if (!node.ref) throw new Error(`Node has no ref`);\n return projectNode(db, node.ref);\n },\n\n async roots() {\n const rows = db.select().from(nodes).where(isNull(nodes.parentRef)).all();\n return rows.map(toStructure);\n },\n };\n}\n","/**\n * Drizzle schema — SQLite tables for RoleX.\n *\n * Five tables:\n * nodes — tree backbone (Structure instances)\n * links — cross-branch relations (bidirectional)\n * prototypes — which prototype packages are settled\n * contexts — per-role session focus state\n * prototype_migrations — Flyway-style migration history\n */\n\nimport { index, integer, primaryKey, sqliteTable, text } from \"drizzle-orm/sqlite-core\";\n\n/**\n * nodes — every node in the society graph.\n *\n * Maps 1:1 to the Structure interface:\n * ref → graph-internal reference (primary key)\n * id → user-facing kebab-case identifier\n * alias → JSON array of alternative names\n * name → structure type (\"individual\", \"goal\", \"task\", etc.)\n * description → what this structure is\n * parent_ref → tree parent (self-referencing foreign key)\n * information → Gherkin Feature source text\n * tag → generic label (\"done\", \"abandoned\")\n */\nexport const nodes = sqliteTable(\n \"nodes\",\n {\n ref: text(\"ref\").primaryKey(),\n id: text(\"id\"),\n alias: text(\"alias\"), // JSON array: '[\"Sean\",\"姜山\"]'\n name: text(\"name\").notNull(),\n description: text(\"description\").default(\"\"),\n parentRef: text(\"parent_ref\").references((): any => nodes.ref),\n information: text(\"information\"),\n tag: text(\"tag\"),\n },\n (table) => [\n index(\"idx_nodes_id\").on(table.id),\n index(\"idx_nodes_name\").on(table.name),\n index(\"idx_nodes_parent_ref\").on(table.parentRef),\n ]\n);\n\n/**\n * links — cross-branch relations between nodes.\n *\n * Bidirectional: if A→B is \"membership\", B→A is \"belong\".\n * Both directions stored as separate rows.\n */\nexport const links = sqliteTable(\n \"links\",\n {\n fromRef: text(\"from_ref\")\n .notNull()\n .references(() => nodes.ref),\n toRef: text(\"to_ref\")\n .notNull()\n .references(() => nodes.ref),\n relation: text(\"relation\").notNull(),\n },\n (table) => [\n primaryKey({ columns: [table.fromRef, table.toRef, table.relation] }),\n index(\"idx_links_from\").on(table.fromRef),\n index(\"idx_links_to\").on(table.toRef),\n ]\n);\n\n/**\n * prototypes — which prototype packages are settled.\n */\nexport const prototypes = sqliteTable(\"prototypes\", {\n id: text(\"id\").primaryKey(),\n source: text(\"source\").notNull(),\n});\n\n/**\n * contexts — per-role session focus state.\n */\nexport const contexts = sqliteTable(\"contexts\", {\n roleId: text(\"role_id\").primaryKey(),\n focusedGoalId: text(\"focused_goal_id\"),\n focusedPlanId: text(\"focused_plan_id\"),\n});\n\n/**\n * prototype_migrations — Flyway-style migration history.\n *\n * Records which migrations have been executed for each prototype.\n */\nexport const prototypeMigrations = sqliteTable(\n \"prototype_migrations\",\n {\n prototypeId: text(\"prototype_id\").notNull(),\n migrationId: text(\"migration_id\").notNull(),\n version: integer(\"version\").notNull(),\n checksum: text(\"checksum\").notNull(),\n executedAt: text(\"executed_at\").notNull(),\n },\n (table) => [primaryKey({ columns: [table.prototypeId, table.migrationId] })]\n);\n","/**\n * Manifest — file-based storage format for RoleX entities.\n *\n * Storage layout:\n * role/<id>/\n * individual.json — manifest (tree structure + links)\n * <id>.<type>.feature — node information (Gherkin)\n *\n * organization/<id>/\n * organization.json — manifest (tree structure + links)\n * <id>.<type>.feature — node information (Gherkin)\n *\n * Rules:\n * - Directories: only role/ and organization/ at top level\n * - Files: all [id].[type].feature, flat within the entity directory\n * - Manifest: tree structure in JSON, content in .feature files\n * - Nodes without explicit id default to their type name\n */\n\nimport type { State } from \"@rolexjs/system\";\n\n// ===== Manifest types =====\n\n/** A node in the manifest tree. */\nexport interface ManifestNode {\n readonly type: string;\n readonly ref?: string;\n readonly tags?: readonly string[];\n readonly children?: Record<string, ManifestNode>;\n readonly links?: Record<string, string[]>;\n}\n\n/** Root manifest for an entity (individual or organization). */\nexport interface Manifest {\n readonly id: string;\n readonly type: string;\n readonly ref?: string;\n readonly alias?: readonly string[];\n readonly children?: Record<string, ManifestNode>;\n readonly links?: Record<string, string[]>;\n}\n\n// ===== State → files =====\n\nexport interface FileEntry {\n readonly path: string;\n readonly content: string;\n}\n\n/**\n * Convert a State tree to a manifest + feature files.\n * Returns the manifest and a list of file entries (path → content).\n */\nexport function stateToFiles(state: State): { manifest: Manifest; files: FileEntry[] } {\n const files: FileEntry[] = [];\n\n const collectFiles = (node: State, nodeId: string) => {\n if (node.information) {\n files.push({\n path: `${nodeId}.${node.name}.feature`,\n content: node.information,\n });\n }\n if (node.children) {\n for (const child of node.children) {\n const childId = child.id ?? child.name;\n collectFiles(child, childId);\n }\n }\n };\n\n const rootId = state.id ?? state.name;\n collectFiles(state, rootId);\n\n const buildManifestNode = (node: State): ManifestNode => {\n const entry: ManifestNode = {\n type: node.name,\n ...(node.ref ? { ref: node.ref } : {}),\n ...(node.tags?.length ? { tags: node.tags } : {}),\n ...(node.links && node.links.length > 0 ? { links: buildManifestLinks(node.links) } : {}),\n };\n if (node.children && node.children.length > 0) {\n const children: Record<string, ManifestNode> = {};\n for (const child of node.children) {\n const childId = child.id ?? child.name;\n children[childId] = buildManifestNode(child);\n }\n return { ...entry, children };\n }\n return entry;\n };\n\n const manifestNode = buildManifestNode(state);\n\n const manifest: Manifest = {\n id: rootId,\n type: state.name,\n ...(state.ref ? { ref: state.ref } : {}),\n ...(state.alias ? { alias: state.alias } : {}),\n ...(manifestNode.children ? { children: manifestNode.children } : {}),\n ...(state.links && state.links.length > 0\n ? {\n links: buildManifestLinks(state.links),\n }\n : {}),\n };\n\n return { manifest, files };\n}\n\nfunction buildManifestLinks(\n links: readonly { readonly relation: string; readonly target: State }[]\n): Record<string, string[]> {\n const result: Record<string, string[]> = {};\n for (const link of links) {\n const targetId = link.target.id ?? link.target.name;\n if (!result[link.relation]) {\n result[link.relation] = [];\n }\n result[link.relation].push(targetId);\n }\n return result;\n}\n\n// ===== Files → State =====\n\n/**\n * Convert a manifest + feature file contents to a State tree.\n * fileContents maps filename (e.g. \"role-creation.principle.feature\") to Gherkin text.\n */\nexport function filesToState(manifest: Manifest, fileContents: Record<string, string>): State {\n const buildState = (id: string, node: ManifestNode): State => {\n const filename = `${id}.${node.type}.feature`;\n const information = fileContents[filename];\n\n const children: State[] = [];\n if (node.children) {\n for (const [childId, childNode] of Object.entries(node.children)) {\n children.push(buildState(childId, childNode));\n }\n }\n\n const nodeLinks: { relation: string; target: State }[] = [];\n if (node.links) {\n for (const [relation, targetIds] of Object.entries(node.links)) {\n for (const targetId of targetIds) {\n nodeLinks.push({\n relation,\n target: { id: targetId, name: \"\", description: \"\", parent: null },\n });\n }\n }\n }\n\n return {\n ...(node.ref ? { ref: node.ref } : {}),\n id,\n name: node.type,\n description: \"\",\n parent: null,\n ...(node.tags?.length ? { tags: node.tags } : {}),\n ...(information ? { information } : {}),\n ...(children.length > 0 ? { children } : {}),\n ...(nodeLinks.length > 0 ? { links: nodeLinks } : {}),\n };\n };\n\n const rootFilename = `${manifest.id}.${manifest.type}.feature`;\n const rootInformation = fileContents[rootFilename];\n\n const children: State[] = [];\n if (manifest.children) {\n for (const [childId, childNode] of Object.entries(manifest.children)) {\n children.push(buildState(childId, childNode));\n }\n }\n\n const links: { relation: string; target: State }[] = [];\n if (manifest.links) {\n for (const [relation, targetIds] of Object.entries(manifest.links)) {\n for (const targetId of targetIds) {\n links.push({\n relation,\n target: {\n id: targetId,\n name: \"\",\n description: \"\",\n parent: null,\n },\n });\n }\n }\n }\n\n return {\n ...(manifest.ref ? { ref: manifest.ref } : {}),\n id: manifest.id,\n ...(manifest.alias ? { alias: manifest.alias } : {}),\n name: manifest.type,\n description: \"\",\n parent: null,\n ...(rootInformation ? { information: rootInformation } : {}),\n ...(children.length > 0 ? { children } : {}),\n ...(links.length > 0 ? { links } : {}),\n };\n}\n"],"mappings":"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","names":["join","max","join","links","children"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rolexjs/local-platform",
3
- "version": "1.5.0-dev-20260317075835",
3
+ "version": "1.5.0",
4
4
  "description": "Local filesystem Platform for RoleX — stores roles in .rolex/ directories",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -22,10 +22,8 @@
22
22
  "dependencies": {
23
23
  "@deepracticex/drizzle": "^0.3.1",
24
24
  "@deepracticex/sqlite": "^0.2.0",
25
- "@issuexjs/node": "^0.2.0",
26
- "@resourcexjs/node-provider": "^2.14.0",
27
- "@rolexjs/core": "1.5.0-dev-20260317075835",
28
- "@rolexjs/system": "1.5.0-dev-20260317075835",
25
+ "@rolexjs/core": "^1.5.0",
26
+ "@rolexjs/system": "^1.5.0",
29
27
  "drizzle-orm": "^0.45.1"
30
28
  },
31
29
  "devDependencies": {},