@elysiumjs/mnemosyne-drizzle 0.2.0 → 0.3.1
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 +60 -0
- package/dist/cache.d.ts +60 -0
- package/dist/cache.js +1 -0
- package/dist/commands/migration_generate.command.js +1 -1
- package/dist/commands/migration_run.command.d.ts +13 -0
- package/dist/commands/migration_run.command.js +6 -11
- package/dist/commands/project.d.ts +11 -0
- package/dist/commands/project.js +1 -0
- package/dist/database.d.ts +55 -23
- package/dist/database.js +1 -1
- package/dist/drizzle.module.d.ts +2 -2
- package/dist/drizzle.module.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/migrations.d.ts +12 -0
- package/dist/migrations.js +2 -1
- package/dist/model.d.ts +5 -5
- package/dist/repository.d.ts +20 -5
- package/dist/repository.js +1 -1
- package/dist/tenancy.d.ts +25 -8
- package/dist/tenancy.js +1 -1
- package/package.json +19 -9
- package/.omc/state/agent-replay-3920b579-6d8e-4f5f-924a-319202936685.jsonl +0 -7
- package/.omc/state/sessions/3920b579-6d8e-4f5f-924a-319202936685/last-tool-error-state.json +0 -7
- package/.omc/state/sessions/3920b579-6d8e-4f5f-924a-319202936685/mission-state.json +0 -93
- package/.omc/state/sessions/3920b579-6d8e-4f5f-924a-319202936685/pre-tool-advisory-throttle.json +0 -18
- package/.omc/state/sessions/3920b579-6d8e-4f5f-924a-319202936685/subagent-tracking-state.json +0 -61
- package/.turbo/turbo-build.log +0 -3
- package/scripts/minify.ts +0 -10
- package/src/commands/migration_generate.command.ts +0 -101
- package/src/commands/migration_run.command.ts +0 -160
- package/src/database.ts +0 -205
- package/src/drizzle.module.ts +0 -97
- package/src/index.ts +0 -47
- package/src/migrations.ts +0 -100
- package/src/model.ts +0 -178
- package/src/repository.ts +0 -113
- package/src/table.ts +0 -70
- package/src/tenancy.ts +0 -249
- package/tests/drizzle.module.test.ts +0 -201
- package/tests/migrations.test.ts +0 -123
- package/tests/model.test.ts +0 -362
- package/tests/setup.ts +0 -0
- package/tests/table.test.ts +0 -72
- package/tests/tenancy.test.ts +0 -212
- package/tsconfig.json +0 -12
package/dist/tenancy.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type { DrizzleConnection } from './database';
|
|
|
6
6
|
* @author Axel Nana <axel.nana@workbud.com>
|
|
7
7
|
* @param tenant The tenant identifier.
|
|
8
8
|
* @returns The tenant's PostgreSQL schema.
|
|
9
|
+
* @throws {Error} If the tenant identifier is malformed.
|
|
9
10
|
*/
|
|
10
11
|
export declare const getTenantSchema: (tenant: string) => PgSchema;
|
|
11
12
|
/**
|
|
@@ -13,6 +14,7 @@ export declare const getTenantSchema: (tenant: string) => PgSchema;
|
|
|
13
14
|
* @author Axel Nana <axel.nana@workbud.com>
|
|
14
15
|
* @param tenant The tenant identifier.
|
|
15
16
|
* @returns The newly registered (or existing) `PgSchema`.
|
|
17
|
+
* @throws {Error} If the tenant identifier is malformed.
|
|
16
18
|
*/
|
|
17
19
|
export declare const registerTenantSchema: (tenant: string) => PgSchema;
|
|
18
20
|
/**
|
|
@@ -26,26 +28,27 @@ export declare const registerTenantSchema: (tenant: string) => PgSchema;
|
|
|
26
28
|
* @param tableName The table name.
|
|
27
29
|
* @param columns The column definitions.
|
|
28
30
|
* @returns A tenant-scoped `PgTable`.
|
|
31
|
+
* @throws {Error} If the tenant identifier is malformed.
|
|
29
32
|
*/
|
|
30
33
|
export declare const wrapTenantSchema: <TTableName extends string, TColumnsMap extends Record<string, AnyPgColumnBuilder>>(tenant: string, tableName: TTableName, columns: TColumnsMap) => PgTable;
|
|
31
34
|
/**
|
|
32
35
|
* Executes a callback within an RLS-scoped transaction for the given tenant.
|
|
36
|
+
*
|
|
37
|
+
* The transaction is registered in the async context, so repositories and
|
|
38
|
+
* `Database.getConnection()` use it inside the callback. When a transaction is already open on the
|
|
39
|
+
* connection, the callback joins it if it is bound to the same tenant. Work for several tenants
|
|
40
|
+
* (such as an admin fan-out) must use one `withRLS()` per tenant, outside any transaction.
|
|
33
41
|
* @author Axel Nana <axel.nana@workbud.com>
|
|
34
42
|
* @param tenant The tenant identifier (or `null` for 'public').
|
|
35
43
|
* @param callback The function to execute within the transaction.
|
|
36
44
|
* @param connectionName The database connection name.
|
|
37
45
|
* @returns The return value of the callback.
|
|
46
|
+
* @throws {TenantMismatchError} If the open transaction is bound to another tenant.
|
|
38
47
|
*/
|
|
39
48
|
export declare const withRLS: <T>(tenant: string | null, callback: (tx: PgAsyncTransaction<any, any>) => Promise<T>, connectionName?: string) => Promise<T>;
|
|
40
49
|
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* @param tenant The tenant identifier (or `null` for 'public').
|
|
44
|
-
* @param connectionName The database connection name.
|
|
45
|
-
*/
|
|
46
|
-
export declare const setConnectionTenant: (tenant: string | null, connectionName?: string) => Promise<void>;
|
|
47
|
-
/**
|
|
48
|
-
* Reads the current tenant from the PostgreSQL session variable.
|
|
50
|
+
* Reads the current tenant from the PostgreSQL tenant variable, on the open transaction when
|
|
51
|
+
* there is one.
|
|
49
52
|
* @author Axel Nana <axel.nana@workbud.com>
|
|
50
53
|
* @param connectionName The database connection name.
|
|
51
54
|
* @returns The current tenant identifier, or `null`.
|
|
@@ -84,5 +87,19 @@ export declare class DrizzleSchemaTenancy implements TenancyStrategy<PgTable, Dr
|
|
|
84
87
|
export declare class DrizzleRLSTenancy implements TenancyStrategy<PgTable, DrizzleConnection> {
|
|
85
88
|
readonly mode = "rls";
|
|
86
89
|
resolveTable(table: PgTable, _tenant: string): PgTable;
|
|
90
|
+
/**
|
|
91
|
+
* Runs a callback in a transaction scoped to the given tenant.
|
|
92
|
+
*
|
|
93
|
+
* The transaction is bound to the tenant for its whole life, registered in the async context
|
|
94
|
+
* for the connection, and the tenant set as the current tenant, for the duration of the
|
|
95
|
+
* callback. When a transaction is already open on the connection, the callback joins it, which
|
|
96
|
+
* is only allowed when that transaction is bound to the same tenant.
|
|
97
|
+
* @author Axel Nana <axel.nana@workbud.com>
|
|
98
|
+
* @param connection The base connection (see `Database.getBaseConnection`).
|
|
99
|
+
* @param tenant The tenant identifier.
|
|
100
|
+
* @param callback The function to execute within the isolated context.
|
|
101
|
+
* @returns The return value of the callback.
|
|
102
|
+
* @throws {TenantMismatchError} If the open transaction is bound to another tenant.
|
|
103
|
+
*/
|
|
87
104
|
withIsolation<T>(connection: DrizzleConnection, tenant: string, callback: () => Promise<T>): Promise<T>;
|
|
88
105
|
}
|
package/dist/tenancy.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getTenancyConfig}from"@elysiumjs/mnemosyne";import{sql}from"drizzle-orm";import{getTableConfig,pgPolicy,pgSchema,pgTable}from"drizzle-orm/pg-core";import{Database}from"./database";import{getTableBuilders}from"./table";const tenantSchemas=new Map;const schemaRegistry=new Map;export const getTenantSchema=(tenant)=>{return schemaRegistry.get(tenant)??registerTenantSchema(tenant)};export const registerTenantSchema=(tenant)=>{if(schemaRegistry.has(tenant)){return schemaRegistry.get(tenant)}const tenantSchema=pgSchema(tenant);schemaRegistry.set(tenant,tenantSchema);return tenantSchema};export const wrapTenantSchema=(tenant,tableName,columns)=>{if(tenant==="public"){return pgTable(tableName,columns)}const fullTableName=`${tenant}.${tableName}`;if(tenantSchemas.has(fullTableName)){return tenantSchemas.get(fullTableName)}const tenantSchema=getTenantSchema(tenant);const schemaTable=tenantSchema.table(tableName,columns);tenantSchemas.set(fullTableName,schemaTable);return schemaTable};export const withRLS=async(tenant,callback,connectionName="default")=>{
|
|
1
|
+
import{getTenancyConfig,isValidTenantId,withTenant}from"@elysiumjs/mnemosyne";import{sql}from"drizzle-orm";import{getTableConfig,pgPolicy,pgSchema,pgTable}from"drizzle-orm/pg-core";import{assertTransactionTenant,bindTransactionTenant,Database}from"./database";import{getTableBuilders}from"./table";const tenantSchemas=new Map;const schemaRegistry=new Map;const assertTenantId=(tenant)=>{if(!isValidTenantId(tenant)){throw new Error(`Invalid tenant identifier: ${JSON.stringify(tenant.slice(0,64))}`)}};export const getTenantSchema=(tenant)=>{assertTenantId(tenant);return schemaRegistry.get(tenant)??registerTenantSchema(tenant)};export const registerTenantSchema=(tenant)=>{assertTenantId(tenant);if(schemaRegistry.has(tenant)){return schemaRegistry.get(tenant)}const tenantSchema=pgSchema(tenant);schemaRegistry.set(tenant,tenantSchema);return tenantSchema};export const wrapTenantSchema=(tenant,tableName,columns)=>{assertTenantId(tenant);if(tenant==="public"){return pgTable(tableName,columns)}const fullTableName=`${tenant}.${tableName}`;if(tenantSchemas.has(fullTableName)){return tenantSchemas.get(fullTableName)}const tenantSchema=getTenantSchema(tenant);const schemaTable=tenantSchema.table(tableName,columns);tenantSchemas.set(fullTableName,schemaTable);return schemaTable};export const withRLS=async(tenant,callback,connectionName="default")=>{return new DrizzleRLSTenancy().withIsolation(Database.getBaseConnection(connectionName),tenant??"public",()=>callback(Database.getConnection(connectionName)))};export const getSessionTenant=async(connectionName="default")=>{const db=Database.getConnection(connectionName);const config=getTenancyConfig();const varName=config.rls?.sessionVariable??"app.current_tenant";const[row]=await db.execute(sql`SELECT current_setting(${varName}, true) as tenant`);return row?.tenant||null};export const createRLSPolicy=(tableName,columnName,policyName)=>{const config=getTenancyConfig();const varName=config.rls?.sessionVariable??"app.current_tenant";const column=columnName??config.rls?.defaultColumn??"tenant_id";const name=policyName??`${tableName}_tenant_isolation`;return pgPolicy(name,{for:"all",to:"public",using:sql`${sql.identifier(column)} = current_setting(${varName}, true)::text`,withCheck:sql`${sql.identifier(column)} = current_setting(${varName}, true)::text`})};export class DrizzleSchemaTenancy{mode="schema";resolveTable(table,tenant){const builders=getTableBuilders(table);if(!builders){throw new Error(`No column builders registered for table. `+`Use pgTable() from '@elysiumjs/mnemosyne-drizzle' for tenant support.`)}const config=getTableConfig(table);return wrapTenantSchema(tenant,config.name,builders)}async withIsolation(_connection,_tenant,callback){return callback()}}export class DrizzleRLSTenancy{mode="rls";resolveTable(table,_tenant){return table}async withIsolation(connection,tenant,callback){const active=Database.getActiveTransaction(connection);if(active!==undefined){assertTransactionTenant(active,tenant);return withTenant(tenant,callback)}return connection.transaction(async(tx)=>{await bindTransactionTenant(tx,tenant);return withTenant(tenant,()=>Database.runInTransaction(connection,tx,callback))})}}
|
package/package.json
CHANGED
|
@@ -1,22 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elysiumjs/mnemosyne-drizzle",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Drizzle ORM driver for @elysiumjs/mnemosyne",
|
|
6
6
|
"private": false,
|
|
7
7
|
"author": "Workbud Technologies Inc.",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
|
-
"url": "https://github.com/
|
|
10
|
+
"url": "git+https://github.com/na2axl/elysiumjs.git",
|
|
11
|
+
"directory": "@elysiumjs/mnemosyne-drizzle"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://github.com/na2axl/elysiumjs/tree/main/@elysiumjs/mnemosyne-drizzle#readme",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/na2axl/elysiumjs/issues"
|
|
11
16
|
},
|
|
12
|
-
"homepage": "https://github.com/workbud/elysium",
|
|
13
17
|
"scripts": {
|
|
14
18
|
"format": "prettier --write \"./src/**/*.ts\"",
|
|
15
19
|
"clean": "rimraf dist",
|
|
16
20
|
"build": "bun run clean && tsc && bun run build:minify",
|
|
17
21
|
"build:minify": "bun scripts/minify.ts",
|
|
18
|
-
"typecheck": "tsc --noEmit",
|
|
19
|
-
"prepublishOnly": "bun run build"
|
|
22
|
+
"typecheck": "tsc --noEmit && tsc -p tsconfig.types.json",
|
|
23
|
+
"prepublishOnly": "bun run build",
|
|
24
|
+
"test": "bun test",
|
|
25
|
+
"test:coverage": "bun test --coverage"
|
|
20
26
|
},
|
|
21
27
|
"keywords": [
|
|
22
28
|
"elysium",
|
|
@@ -28,10 +34,14 @@
|
|
|
28
34
|
"module": "dist/index.js",
|
|
29
35
|
"type": "module",
|
|
30
36
|
"types": "dist/index.d.ts",
|
|
37
|
+
"files": [
|
|
38
|
+
"dist",
|
|
39
|
+
"CHANGELOG.md"
|
|
40
|
+
],
|
|
31
41
|
"sideEffects": false,
|
|
32
42
|
"peerDependencies": {
|
|
33
|
-
"@elysiumjs/core": "^0.
|
|
34
|
-
"@elysiumjs/mnemosyne": "^0.
|
|
43
|
+
"@elysiumjs/core": "^0.10.0",
|
|
44
|
+
"@elysiumjs/mnemosyne": "^0.3.1"
|
|
35
45
|
},
|
|
36
46
|
"dependencies": {
|
|
37
47
|
"drizzle-orm": "^1.0.0-rc.5",
|
|
@@ -40,7 +50,7 @@
|
|
|
40
50
|
},
|
|
41
51
|
"devDependencies": {
|
|
42
52
|
"@types/prompts": "^2.4.9",
|
|
43
|
-
"@elysiumjs/core": "0.
|
|
44
|
-
"@elysiumjs/mnemosyne": "0.
|
|
53
|
+
"@elysiumjs/core": "0.10.0",
|
|
54
|
+
"@elysiumjs/mnemosyne": "0.3.1"
|
|
45
55
|
}
|
|
46
56
|
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{"t":0,"agent":"aac206b","agent_type":"executor","event":"agent_start","parent_mode":"none"}
|
|
2
|
-
{"t":0,"agent":"a914068","agent_type":"executor","event":"agent_stop","success":true,"duration_ms":31478}
|
|
3
|
-
{"t":0,"agent":"aa0cc16","agent_type":"untracked-native-fork","event":"agent_stop","success":true,"synthetic":true,"telemetry_status":"unmatched_stop","reason":"SubagentStop arrived without a matching SubagentStart; native Agent/Task start telemetry was not observed."}
|
|
4
|
-
{"t":0,"agent":"a55f688","agent_type":"untracked-native-fork","event":"agent_stop","success":true,"synthetic":true,"telemetry_status":"unmatched_stop","reason":"SubagentStop arrived without a matching SubagentStart; native Agent/Task start telemetry was not observed."}
|
|
5
|
-
{"t":0,"agent":"a0ba584","agent_type":"untracked-native-fork","event":"agent_stop","success":true,"synthetic":true,"telemetry_status":"unmatched_stop","reason":"SubagentStop arrived without a matching SubagentStart; native Agent/Task start telemetry was not observed."}
|
|
6
|
-
{"t":0,"agent":"a6e8774","agent_type":"untracked-native-fork","event":"agent_stop","success":true,"synthetic":true,"telemetry_status":"unmatched_stop","reason":"SubagentStop arrived without a matching SubagentStart; native Agent/Task start telemetry was not observed."}
|
|
7
|
-
{"t":0,"agent":"aac206b","agent_type":"executor","event":"agent_stop","success":true,"duration_ms":168112}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"tool_name": "Bash",
|
|
3
|
-
"tool_input_preview": "{\"command\":\"perl -0pi -e 's/\\\\t\\\\t\\\\tconst migrations: \\\\{ name: string \\\\}\\\\[\\\\] = await sql`SELECT name FROM elysium_migrations;`;\\\\n\\\\t\\\\t\\\\tconst completedMigrations = migrations\\\\.map\\\\(\\\\(row\\\\)...",
|
|
4
|
-
"error": "Exit code 1\n\t\t\t}\n\n\t\t\tconst rows: { name: string; applied_at: Date }[] =\n\t\t\t\tawait sql`SELECT name, applied_at FROM elysium_migrations;`;\n\t\t\tconst completedMigrations = rows.map((row) => ({ name: row.name, appliedAt: row.applied_at }));\n\n\t\t\tconst filesIt = new Bun.Glob(`./src/database/migrations/**/*.sql`).scan({\n\t\t\t\tabsolute: true,\n\t\t\t\tonlyFiles: true\n\t\t\t});\n\n\t\t\tconst files = await Array.fromAsync(filesIt);\n\t\t\tconst { pending: sqlFiles, renames } = planMigrations(files, completedMigrations);\nChe...",
|
|
5
|
-
"timestamp": "2026-10-26T02:29:07.154Z",
|
|
6
|
-
"retry_count": 1
|
|
7
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"updatedAt": "2026-10-24T23:32:53.900Z",
|
|
3
|
-
"missions": [
|
|
4
|
-
{
|
|
5
|
-
"id": "session:3920b579-6d8e-4f5f-924a-319202936685:none",
|
|
6
|
-
"source": "session",
|
|
7
|
-
"name": "none",
|
|
8
|
-
"objective": "Session mission",
|
|
9
|
-
"createdAt": "2026-10-24T23:30:05.788Z",
|
|
10
|
-
"updatedAt": "2026-10-24T23:32:53.900Z",
|
|
11
|
-
"status": "done",
|
|
12
|
-
"workerCount": 1,
|
|
13
|
-
"taskCounts": {
|
|
14
|
-
"total": 1,
|
|
15
|
-
"pending": 0,
|
|
16
|
-
"blocked": 0,
|
|
17
|
-
"inProgress": 0,
|
|
18
|
-
"completed": 1,
|
|
19
|
-
"failed": 0
|
|
20
|
-
},
|
|
21
|
-
"agents": [
|
|
22
|
-
{
|
|
23
|
-
"name": "executor:aac206b",
|
|
24
|
-
"role": "executor",
|
|
25
|
-
"ownership": "aac206b9ab7956eb4",
|
|
26
|
-
"status": "done",
|
|
27
|
-
"currentStep": null,
|
|
28
|
-
"latestUpdate": "completed",
|
|
29
|
-
"completedSummary": null,
|
|
30
|
-
"updatedAt": "2026-10-24T23:32:53.900Z"
|
|
31
|
-
}
|
|
32
|
-
],
|
|
33
|
-
"timeline": [
|
|
34
|
-
{
|
|
35
|
-
"id": "session-start:aac206b9ab7956eb4:2026-10-24T23:30:05.788Z",
|
|
36
|
-
"at": "2026-10-24T23:30:05.788Z",
|
|
37
|
-
"kind": "update",
|
|
38
|
-
"agent": "executor:aac206b",
|
|
39
|
-
"detail": "started executor:aac206b",
|
|
40
|
-
"sourceKey": "session-start:aac206b9ab7956eb4"
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
"id": "session-stop:a914068b2d3b26e56:2026-10-24T23:30:37.266Z",
|
|
44
|
-
"at": "2026-10-24T23:30:37.266Z",
|
|
45
|
-
"kind": "completion",
|
|
46
|
-
"agent": "executor:aac206b",
|
|
47
|
-
"detail": "completed",
|
|
48
|
-
"sourceKey": "session-stop:a914068b2d3b26e56"
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
"id": "session-stop:aa0cc16535a1e4c83:2026-10-24T23:31:08.989Z",
|
|
52
|
-
"at": "2026-10-24T23:31:08.989Z",
|
|
53
|
-
"kind": "completion",
|
|
54
|
-
"agent": "executor:aac206b",
|
|
55
|
-
"detail": "completed",
|
|
56
|
-
"sourceKey": "session-stop:aa0cc16535a1e4c83"
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
"id": "session-stop:a55f6887513d75db7:2026-10-24T23:31:40.515Z",
|
|
60
|
-
"at": "2026-10-24T23:31:40.515Z",
|
|
61
|
-
"kind": "completion",
|
|
62
|
-
"agent": "executor:aac206b",
|
|
63
|
-
"detail": "completed",
|
|
64
|
-
"sourceKey": "session-stop:a55f6887513d75db7"
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
"id": "session-stop:a0ba584b3d851e834:2026-10-24T23:32:12.704Z",
|
|
68
|
-
"at": "2026-10-24T23:32:12.704Z",
|
|
69
|
-
"kind": "completion",
|
|
70
|
-
"agent": "executor:aac206b",
|
|
71
|
-
"detail": "completed",
|
|
72
|
-
"sourceKey": "session-stop:a0ba584b3d851e834"
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
"id": "session-stop:a6e8774450f70f52b:2026-10-24T23:32:44.262Z",
|
|
76
|
-
"at": "2026-10-24T23:32:44.262Z",
|
|
77
|
-
"kind": "completion",
|
|
78
|
-
"agent": "executor:aac206b",
|
|
79
|
-
"detail": "completed",
|
|
80
|
-
"sourceKey": "session-stop:a6e8774450f70f52b"
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
"id": "session-stop:aac206b9ab7956eb4:2026-10-24T23:32:53.900Z",
|
|
84
|
-
"at": "2026-10-24T23:32:53.900Z",
|
|
85
|
-
"kind": "completion",
|
|
86
|
-
"agent": "executor:aac206b",
|
|
87
|
-
"detail": "completed",
|
|
88
|
-
"sourceKey": "session-stop:aac206b9ab7956eb4"
|
|
89
|
-
}
|
|
90
|
-
]
|
|
91
|
-
}
|
|
92
|
-
]
|
|
93
|
-
}
|
package/.omc/state/sessions/3920b579-6d8e-4f5f-924a-319202936685/pre-tool-advisory-throttle.json
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 1,
|
|
3
|
-
"entries": {
|
|
4
|
-
"445ed27a3872b681d98190bae61ccb84954e1bc4e140df5370be958dee776b3a": {
|
|
5
|
-
"last_emitted_at_ms": 1792981759903,
|
|
6
|
-
"message": "Verify changes work after editing. Test functionality before marking complete."
|
|
7
|
-
},
|
|
8
|
-
"79a93d4a2f8f50b95f852280616242fee1855dc99a3c75211917f55e72e95fae": {
|
|
9
|
-
"last_emitted_at_ms": 1792981745167,
|
|
10
|
-
"message": "Use parallel execution for independent tasks. Use run_in_background for long operations (npm install, builds, tests)."
|
|
11
|
-
},
|
|
12
|
-
"466399dafa2d20f60587180bad0a07358eb7f2bce724df0ff682f038ad33f5ad": {
|
|
13
|
-
"last_emitted_at_ms": 1792981448165,
|
|
14
|
-
"message": "Read multiple files in parallel when possible for faster analysis."
|
|
15
|
-
}
|
|
16
|
-
},
|
|
17
|
-
"updated_at": "2026-10-26T02:29:19.903Z"
|
|
18
|
-
}
|
package/.omc/state/sessions/3920b579-6d8e-4f5f-924a-319202936685/subagent-tracking-state.json
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"agents": [
|
|
3
|
-
{
|
|
4
|
-
"agent_id": "aac206b9ab7956eb4",
|
|
5
|
-
"agent_type": "oh-my-claudecode:executor",
|
|
6
|
-
"started_at": "2026-10-24T23:30:05.788Z",
|
|
7
|
-
"parent_mode": "none",
|
|
8
|
-
"status": "completed",
|
|
9
|
-
"completed_at": "2026-10-24T23:32:53.900Z",
|
|
10
|
-
"duration_ms": 168112
|
|
11
|
-
},
|
|
12
|
-
{
|
|
13
|
-
"agent_id": "aa0cc16535a1e4c83",
|
|
14
|
-
"agent_type": "untracked-native-fork",
|
|
15
|
-
"started_at": "2026-10-24T23:31:08.989Z",
|
|
16
|
-
"parent_mode": "none",
|
|
17
|
-
"status": "completed",
|
|
18
|
-
"completed_at": "2026-10-24T23:31:08.989Z",
|
|
19
|
-
"synthetic": true,
|
|
20
|
-
"telemetry_status": "unmatched_stop",
|
|
21
|
-
"telemetry_note": "SubagentStop arrived without a matching SubagentStart; native Agent/Task start telemetry was not observed."
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
"agent_id": "a55f6887513d75db7",
|
|
25
|
-
"agent_type": "untracked-native-fork",
|
|
26
|
-
"started_at": "2026-10-24T23:31:40.515Z",
|
|
27
|
-
"parent_mode": "none",
|
|
28
|
-
"status": "completed",
|
|
29
|
-
"completed_at": "2026-10-24T23:31:40.515Z",
|
|
30
|
-
"synthetic": true,
|
|
31
|
-
"telemetry_status": "unmatched_stop",
|
|
32
|
-
"telemetry_note": "SubagentStop arrived without a matching SubagentStart; native Agent/Task start telemetry was not observed."
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
"agent_id": "a0ba584b3d851e834",
|
|
36
|
-
"agent_type": "untracked-native-fork",
|
|
37
|
-
"started_at": "2026-10-24T23:32:12.704Z",
|
|
38
|
-
"parent_mode": "none",
|
|
39
|
-
"status": "completed",
|
|
40
|
-
"completed_at": "2026-10-24T23:32:12.704Z",
|
|
41
|
-
"synthetic": true,
|
|
42
|
-
"telemetry_status": "unmatched_stop",
|
|
43
|
-
"telemetry_note": "SubagentStop arrived without a matching SubagentStart; native Agent/Task start telemetry was not observed."
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
"agent_id": "a6e8774450f70f52b",
|
|
47
|
-
"agent_type": "untracked-native-fork",
|
|
48
|
-
"started_at": "2026-10-24T23:32:44.262Z",
|
|
49
|
-
"parent_mode": "none",
|
|
50
|
-
"status": "completed",
|
|
51
|
-
"completed_at": "2026-10-24T23:32:44.262Z",
|
|
52
|
-
"synthetic": true,
|
|
53
|
-
"telemetry_status": "unmatched_stop",
|
|
54
|
-
"telemetry_note": "SubagentStop arrived without a matching SubagentStart; native Agent/Task start telemetry was not observed."
|
|
55
|
-
}
|
|
56
|
-
],
|
|
57
|
-
"total_spawned": 1,
|
|
58
|
-
"total_completed": 6,
|
|
59
|
-
"total_failed": 0,
|
|
60
|
-
"last_updated": "2026-10-24T23:32:53.907Z"
|
|
61
|
-
}
|
package/.turbo/turbo-build.log
DELETED
package/scripts/minify.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { Glob } from 'bun';
|
|
2
|
-
|
|
3
|
-
const glob = new Glob('dist/**/*.js');
|
|
4
|
-
|
|
5
|
-
for await (const path of glob.scan('.')) {
|
|
6
|
-
const file = Bun.file(path);
|
|
7
|
-
const code = await file.text();
|
|
8
|
-
const result = new Bun.Transpiler({ minifyWhitespace: true, trimUnusedImports: true }).transformSync(code);
|
|
9
|
-
await Bun.write(file, result);
|
|
10
|
-
}
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2025-present Workbud Technologies Inc. All rights reserved.
|
|
2
|
-
//
|
|
3
|
-
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
// you may not use this file except in compliance with the License.
|
|
5
|
-
// You may obtain a copy of the License at
|
|
6
|
-
//
|
|
7
|
-
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
//
|
|
9
|
-
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
// See the License for the specific language governing permissions and
|
|
13
|
-
// limitations under the License.
|
|
14
|
-
|
|
15
|
-
import { existsSync } from 'node:fs';
|
|
16
|
-
import { exists } from 'node:fs/promises';
|
|
17
|
-
import { dirname, join } from 'node:path';
|
|
18
|
-
|
|
19
|
-
import { Command, CommandArgumentType } from '@elysiumjs/core';
|
|
20
|
-
import prompts from 'prompts';
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Gets the root path of the Elysium.js project: the closest parent holding an `.elysiumrc`.
|
|
24
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
25
|
-
*/
|
|
26
|
-
const getProjectPath = () => {
|
|
27
|
-
const startPath = process.cwd();
|
|
28
|
-
let dir = startPath;
|
|
29
|
-
|
|
30
|
-
while (true) {
|
|
31
|
-
if (existsSync(join(dir, '.elysiumrc'))) return dir;
|
|
32
|
-
|
|
33
|
-
const parentDir = dirname(dir);
|
|
34
|
-
if (dir === parentDir) break;
|
|
35
|
-
|
|
36
|
-
dir = parentDir;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return startPath;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Generates migration files.
|
|
44
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
45
|
-
*/
|
|
46
|
-
@Command.register()
|
|
47
|
-
export class MigrationGenerateCommand extends Command {
|
|
48
|
-
public static readonly command: string = 'migration:generate';
|
|
49
|
-
public static readonly description: string = 'Generates migration files.';
|
|
50
|
-
|
|
51
|
-
@Command.arg({
|
|
52
|
-
description: 'The name of the migration to create',
|
|
53
|
-
type: CommandArgumentType.STRING
|
|
54
|
-
})
|
|
55
|
-
private name?: string;
|
|
56
|
-
|
|
57
|
-
public async run(): Promise<void> {
|
|
58
|
-
if (!this.name) {
|
|
59
|
-
const answers = await prompts(
|
|
60
|
-
[
|
|
61
|
-
{
|
|
62
|
-
type: 'text',
|
|
63
|
-
name: 'name',
|
|
64
|
-
message: 'Migration Name:',
|
|
65
|
-
initial: 'create_users_table',
|
|
66
|
-
validate(value: string) {
|
|
67
|
-
if (value.length < 1) {
|
|
68
|
-
return 'Migration name cannot be empty';
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return true;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
],
|
|
75
|
-
{
|
|
76
|
-
onCancel: () => {
|
|
77
|
-
this.error('Operation cancelled.');
|
|
78
|
-
process.exit(0);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
);
|
|
82
|
-
|
|
83
|
-
this.name = answers.name;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const projectRoot = getProjectPath();
|
|
87
|
-
let schemaPath = `${projectRoot}/src/database/schemas`;
|
|
88
|
-
if (await exists(`${projectRoot}/src/database/schema.ts`)) {
|
|
89
|
-
schemaPath = `${projectRoot}/src/database/schema.ts`;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
await Bun.$`bunx --bun drizzle-kit generate --dialect postgresql --schema ${schemaPath} --out ${projectRoot}/src/database/migrations --name ${this.name}`;
|
|
93
|
-
|
|
94
|
-
const sqlFiles = new Bun.Glob(`${projectRoot}/src/database/migrations/**/*.sql`).scan();
|
|
95
|
-
for await (const path of sqlFiles) {
|
|
96
|
-
const file = Bun.file(path);
|
|
97
|
-
const content = await file.text();
|
|
98
|
-
await file.write(content.replace(/"public"\./gm, ''));
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2025-present Workbud Technologies Inc. All rights reserved.
|
|
2
|
-
//
|
|
3
|
-
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
// you may not use this file except in compliance with the License.
|
|
5
|
-
// You may obtain a copy of the License at
|
|
6
|
-
//
|
|
7
|
-
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
//
|
|
9
|
-
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
// See the License for the specific language governing permissions and
|
|
13
|
-
// limitations under the License.
|
|
14
|
-
|
|
15
|
-
import { Command, CommandArgumentType } from '@elysiumjs/core';
|
|
16
|
-
import prompts from 'prompts';
|
|
17
|
-
|
|
18
|
-
import { Database } from '../database';
|
|
19
|
-
import { getMigrationName, planMigrations } from '../migrations';
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Execute migration files.
|
|
23
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
24
|
-
*/
|
|
25
|
-
@Command.register()
|
|
26
|
-
export class MigrationRunCommand extends Command {
|
|
27
|
-
public static readonly command: string = 'migration:run';
|
|
28
|
-
public static readonly description: string = 'Runs pending migrations.';
|
|
29
|
-
|
|
30
|
-
@Command.arg({
|
|
31
|
-
description: 'The name of the tenant in which the migrations will be executed.',
|
|
32
|
-
type: CommandArgumentType.STRING,
|
|
33
|
-
required: true
|
|
34
|
-
})
|
|
35
|
-
private tenant: string = '';
|
|
36
|
-
|
|
37
|
-
@Command.arg({
|
|
38
|
-
description: 'The name of the connection to use.',
|
|
39
|
-
type: CommandArgumentType.STRING,
|
|
40
|
-
default: 'default'
|
|
41
|
-
})
|
|
42
|
-
private connection: string = 'default';
|
|
43
|
-
|
|
44
|
-
@Command.arg({
|
|
45
|
-
description: 'Drop the entire schema before running the migrations.',
|
|
46
|
-
type: CommandArgumentType.BOOLEAN,
|
|
47
|
-
default: false
|
|
48
|
-
})
|
|
49
|
-
private fresh: boolean = false;
|
|
50
|
-
|
|
51
|
-
public async run(): Promise<void> {
|
|
52
|
-
if (!Database.connectionExists(this.connection)) {
|
|
53
|
-
this.error(`Connection ${this.bold(this.connection)} does not exist.`);
|
|
54
|
-
return process.exit(1);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const sql = Database.getConnection(this.connection).$client;
|
|
58
|
-
await sql.connect();
|
|
59
|
-
|
|
60
|
-
await sql.begin(async (sql: Bun.SQL) => {
|
|
61
|
-
if (this.fresh) {
|
|
62
|
-
await sql`DROP SCHEMA IF EXISTS ${sql(this.tenant)} CASCADE;`;
|
|
63
|
-
await sql`CREATE SCHEMA ${sql(this.tenant)};`;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const [{ schema_exists }] = await sql`SELECT EXISTS (
|
|
67
|
-
SELECT schema_name
|
|
68
|
-
FROM information_schema.schemata
|
|
69
|
-
WHERE schema_name = ${this.tenant}
|
|
70
|
-
) AS schema_exists;`;
|
|
71
|
-
|
|
72
|
-
if (!schema_exists) {
|
|
73
|
-
const answers = await prompts(
|
|
74
|
-
[
|
|
75
|
-
{
|
|
76
|
-
type: 'confirm',
|
|
77
|
-
name: 'create',
|
|
78
|
-
message: `Schema ${this.tenant} does not exist. Do you want to create it?`,
|
|
79
|
-
initial: true
|
|
80
|
-
}
|
|
81
|
-
],
|
|
82
|
-
{
|
|
83
|
-
onCancel: () => {
|
|
84
|
-
this.error('Operation cancelled.');
|
|
85
|
-
process.exit(0);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
if (answers.create) {
|
|
91
|
-
await sql`CREATE SCHEMA ${sql(this.tenant)};`;
|
|
92
|
-
} else {
|
|
93
|
-
this.error(`Schema ${this.bold(this.tenant)} creation cancelled.`);
|
|
94
|
-
return process.exit(1);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
await sql`SET search_path TO ${sql(this.tenant)};`;
|
|
99
|
-
|
|
100
|
-
const [{ table_exists }] = await sql`SELECT EXISTS (
|
|
101
|
-
SELECT *
|
|
102
|
-
FROM information_schema.tables
|
|
103
|
-
WHERE table_name = 'elysium_migrations'
|
|
104
|
-
AND table_schema = ${this.tenant}
|
|
105
|
-
) AS table_exists;`;
|
|
106
|
-
|
|
107
|
-
if (!table_exists) {
|
|
108
|
-
await sql`CREATE TABLE elysium_migrations (
|
|
109
|
-
id SERIAL PRIMARY KEY,
|
|
110
|
-
name TEXT NOT NULL,
|
|
111
|
-
batch INTEGER NOT NULL,
|
|
112
|
-
applied_at TIMESTAMP NOT NULL
|
|
113
|
-
);`;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const rows: { name: string; applied_at: Date }[] =
|
|
117
|
-
await sql`SELECT name, applied_at FROM elysium_migrations;`;
|
|
118
|
-
const completedMigrations = rows.map((row) => ({
|
|
119
|
-
name: row.name,
|
|
120
|
-
appliedAt: row.applied_at
|
|
121
|
-
}));
|
|
122
|
-
|
|
123
|
-
const filesIt = new Bun.Glob(`./src/database/migrations/**/*.sql`).scan({
|
|
124
|
-
absolute: true,
|
|
125
|
-
onlyFiles: true
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
const files = await Array.fromAsync(filesIt);
|
|
129
|
-
const { pending: sqlFiles, renames } = planMigrations(files, completedMigrations);
|
|
130
|
-
|
|
131
|
-
for (const { from, to } of renames) {
|
|
132
|
-
await sql`UPDATE elysium_migrations SET name = ${to} WHERE name = ${from};`;
|
|
133
|
-
this.info(`Migration ${this.bold(from)} is now tracked as ${this.bold(to)}.`);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (sqlFiles.length === 0) {
|
|
137
|
-
this.success('No new migrations to apply.');
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const s = this.spinner(`Running migrations for tenant ${this.bold(this.tenant)}...`);
|
|
142
|
-
|
|
143
|
-
const [{ max }]: [{ max?: number }] =
|
|
144
|
-
await sql`SELECT MAX(batch) + 1 AS max FROM elysium_migrations;`;
|
|
145
|
-
|
|
146
|
-
const batch = max ?? 0;
|
|
147
|
-
|
|
148
|
-
for (const path of sqlFiles) {
|
|
149
|
-
await sql.file(path);
|
|
150
|
-
const [{ name }] =
|
|
151
|
-
await sql`INSERT INTO elysium_migrations (name, batch, applied_at) VALUES (${getMigrationName(path)}, ${batch}, ${new Date()}) RETURNING name;`;
|
|
152
|
-
s.pause(`Migration ${this.bold(name)} applied successfully.`);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
s.complete(`Migrations for tenant ${this.bold(this.tenant)} applied successfully.`);
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
await sql.close();
|
|
159
|
-
}
|
|
160
|
-
}
|