@ykurilov/agent-chat-skills 0.57.0 → 0.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/dist/postgres.js +6 -11
- package/dist/postgres.js.map +1 -1
- package/dist/types/store/postgres.d.ts +2 -2
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @ykurilov/agent-chat-skills
|
|
2
2
|
|
|
3
|
+
## 0.58.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 760962e: Хранилища пакетов на PostgreSQL можно открывать одновременно на совсем пустой базе. Раньше пакеты разом создавали
|
|
8
|
+
схему `agent_chat`, проигравший падал на `CREATE SCHEMA IF NOT EXISTS`, и его хранилище не работало до перезапуска.
|
|
9
|
+
Теперь схема создаётся под общей блокировкой всех пакетов, она держится только на создании схемы. Миграции идут под
|
|
10
|
+
своей блокировкой пакета: разные пакеты друг друга не ждут, взаимной блокировки нет. Столкновение «такое уже есть»
|
|
11
|
+
повторяется само. Новое в core: `migratePostgresSchema({ connect, lockKey, migrate })` — для своих пакетов на той же
|
|
12
|
+
схеме.
|
|
13
|
+
|
|
14
|
+
### Как обновить приложение
|
|
15
|
+
|
|
16
|
+
Ничего делать не нужно.
|
|
17
|
+
- Updated dependencies [332d90e]
|
|
18
|
+
- Updated dependencies [2ed600d]
|
|
19
|
+
- Updated dependencies [760962e]
|
|
20
|
+
- @ykurilov/agent-chat-core@0.58.0
|
|
21
|
+
|
|
3
22
|
## 0.57.0
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
package/dist/postgres.js
CHANGED
|
@@ -18,6 +18,7 @@ import { fileURLToPath } from "url";
|
|
|
18
18
|
import { and, count, desc, eq, getTableColumns } from "drizzle-orm";
|
|
19
19
|
import { drizzle } from "drizzle-orm/node-postgres";
|
|
20
20
|
import { migrate } from "drizzle-orm/node-postgres/migrator";
|
|
21
|
+
import { migratePostgresSchema } from "@ykurilov/agent-chat-core";
|
|
21
22
|
|
|
22
23
|
// src/store/postgres-schema.ts
|
|
23
24
|
import { bigserial, index, integer, pgSchema, primaryKey, text, timestamp } from "drizzle-orm/pg-core";
|
|
@@ -75,17 +76,11 @@ function toLoad({ id: _id, ...row }) {
|
|
|
75
76
|
return { ...row, loadedAt: row.loadedAt.toISOString() };
|
|
76
77
|
}
|
|
77
78
|
async function migrateSkillsToLatest(pool, migrationsFolder) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
} finally {
|
|
84
|
-
await client.query("select pg_advisory_unlock($1)", [SKILLS_MIGRATION_LOCK_KEY]);
|
|
85
|
-
}
|
|
86
|
-
} finally {
|
|
87
|
-
client.release();
|
|
88
|
-
}
|
|
79
|
+
await migratePostgresSchema({
|
|
80
|
+
connect: () => pool.connect(),
|
|
81
|
+
lockKey: SKILLS_MIGRATION_LOCK_KEY,
|
|
82
|
+
migrate: (client) => migrate(drizzle(client), { migrationsFolder, migrationsSchema: "agent_chat", migrationsTable: SKILLS_MIGRATIONS_TABLE })
|
|
83
|
+
});
|
|
89
84
|
}
|
|
90
85
|
function createPostgresSkillStore(pool, migrationsFolder) {
|
|
91
86
|
const db = drizzle(pool);
|
package/dist/postgres.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/postgres.ts","../src/store/postgres.ts","../src/store/postgres-schema.ts"],"sourcesContent":["import { fileURLToPath } from \"node:url\";\nimport type { Pool } from \"pg\";\nimport type { SkillStore } from \"./types\";\nimport { createPostgresSkillStore } from \"./store/postgres\";\n\nexport { SKILLS_MIGRATION_LOCK_KEY, SKILLS_MIGRATIONS_TABLE } from \"./store/migration-settings\";\nexport { skillLoads, skills, skillVersions } from \"./store/postgres-schema\";\n\n/** Миграции лежат в пакете рядом с `dist`: `drizzle/postgres`. */\nconst MIGRATIONS_FOLDER = fileURLToPath(new URL(\"../drizzle/postgres\", import.meta.url));\n\n/**\n * Навыки в PostgreSQL на пуле приложения (схема `agent_chat`, та же база, что у хранилища чатов).\n * Таблицы приводятся к последней миграции при первом обращении. Пул закрывает приложение.\n */\nexport function postgresSkillStore(pool: Pool): SkillStore {\n return createPostgresSkillStore(pool, MIGRATIONS_FOLDER);\n}\n","import { and, count, desc, eq, getTableColumns } from \"drizzle-orm\";\nimport { drizzle } from \"drizzle-orm/node-postgres\";\nimport { migrate } from \"drizzle-orm/node-postgres/migrator\";\nimport type { Pool } from \"pg\";\nimport { SkillExistsError, SkillNotFoundError, SkillVersionConflictError } from \"../types\";\nimport type { Skill, SkillBrief, SkillLoad, SkillStore, SkillVersion } from \"../types\";\nimport { SKILLS_MIGRATION_LOCK_KEY, SKILLS_MIGRATIONS_TABLE } from \"./migration-settings\";\nimport { skillLoads, skills, skillVersions } from \"./postgres-schema\";\nimport { byName, sameText, storedText } from \"./skill-store\";\n\nfunction toSkill(row: typeof skills.$inferSelect): Skill {\n return { ...row, createdAt: row.createdAt.toISOString(), updatedAt: row.updatedAt.toISOString() };\n}\n\nconst { body: _body, ...briefColumns } = getTableColumns(skills);\n\nfunction toBrief(row: Omit<typeof skills.$inferSelect, \"body\">): SkillBrief {\n return { ...row, createdAt: row.createdAt.toISOString(), updatedAt: row.updatedAt.toISOString() };\n}\n\nfunction toVersion(row: typeof skillVersions.$inferSelect): SkillVersion {\n return { ...row, createdAt: row.createdAt.toISOString() };\n}\n\nfunction toLoad({ id: _id, ...row }: typeof skillLoads.$inferSelect): SkillLoad {\n return { ...row, loadedAt: row.loadedAt.toISOString() };\n}\n\n/**\n * Приводит таблицы навыков к последней миграции. Идёт на одном соединении под блокировкой базы:\n * если несколько серверов стартуют сразу, второй ждёт первого и видит применённые миграции.\n */\nexport async function migrateSkillsToLatest(pool: Pool, migrationsFolder: string): Promise<void> {\n const client = await pool.connect();\n try {\n await client.query(\"select pg_advisory_lock($1)\", [SKILLS_MIGRATION_LOCK_KEY]);\n try {\n await migrate(drizzle(client), { migrationsFolder, migrationsSchema: \"agent_chat\", migrationsTable: SKILLS_MIGRATIONS_TABLE });\n } finally {\n await client.query(\"select pg_advisory_unlock($1)\", [SKILLS_MIGRATION_LOCK_KEY]);\n }\n } finally {\n client.release();\n }\n}\n\n/**\n * Навыки в PostgreSQL (схема `agent_chat`) на пуле приложения. Миграция идёт при первом обращении, каждая операция\n * её дожидается. Правка и её версия — в одной транзакции с условием на номер версии. Пул закрывает приложение.\n */\nexport function createPostgresSkillStore(pool: Pool, migrationsFolder: string): SkillStore {\n const db = drizzle(pool);\n const ready = migrateSkillsToLatest(pool, migrationsFolder);\n // Ошибка миграции придёт в каждую операцию; без этого она всплыла бы ещё и как необработанная.\n ready.catch(() => {});\n\n async function get(name: string): Promise<Skill | null> {\n await ready;\n const [row] = await db.select().from(skills).where(eq(skills.name, name));\n return row ? toSkill(row) : null;\n }\n\n return {\n async list() {\n await ready;\n return (await db.select().from(skills)).map(toSkill).sort(byName);\n },\n async listBrief() {\n await ready;\n return (await db.select(briefColumns).from(skills)).map(toBrief).sort(byName);\n },\n get,\n async create(input, at) {\n await ready;\n const text = storedText(input);\n return db.transaction(async (tx) => {\n const [row] = await tx\n .insert(skills)\n .values({ name: input.name, ...text, status: input.status, version: 1, createdBy: input.author, createdAt: new Date(at), updatedBy: input.author, updatedAt: new Date(at) })\n .onConflictDoNothing()\n .returning();\n if (!row) throw new SkillExistsError(input.name);\n await tx.insert(skillVersions).values({ name: input.name, version: 1, ...text, author: input.author, createdAt: new Date(at) });\n return toSkill(row);\n });\n },\n async updateText(name, edit, at) {\n await ready;\n const text = storedText(edit);\n return db.transaction(async (tx) => {\n const [current] = await tx.select().from(skills).where(eq(skills.name, name));\n if (!current) throw new SkillNotFoundError(name);\n if (current.version !== edit.expectedVersion) throw new SkillVersionConflictError(name, current.version);\n if (sameText(toSkill(current), text)) return toSkill(current);\n const version = current.version + 1;\n // Условие на версию — в том же `update … where`: соперник, успевший первым, оставит здесь ноль строк.\n const [row] = await tx\n .update(skills)\n .set({ ...text, version, updatedBy: edit.author, updatedAt: new Date(at) })\n .where(and(eq(skills.name, name), eq(skills.version, edit.expectedVersion)))\n .returning();\n if (!row) {\n const [latest] = await db.select({ version: skills.version }).from(skills).where(eq(skills.name, name));\n if (!latest) throw new SkillNotFoundError(name);\n throw new SkillVersionConflictError(name, latest.version);\n }\n await tx.insert(skillVersions).values({ name, version, ...text, author: edit.author, createdAt: new Date(at) });\n return toSkill(row);\n });\n },\n async setStatus(name, status, author, at) {\n await ready;\n const [row] = await db.update(skills).set({ status, updatedBy: author, updatedAt: new Date(at) }).where(eq(skills.name, name)).returning();\n if (!row) throw new SkillNotFoundError(name);\n return toSkill(row);\n },\n async delete(name) {\n await ready;\n return db.transaction(async (tx) => {\n await tx.delete(skillLoads).where(eq(skillLoads.name, name));\n await tx.delete(skillVersions).where(eq(skillVersions.name, name));\n const removed = await tx.delete(skills).where(eq(skills.name, name)).returning({ name: skills.name });\n return removed.length > 0;\n });\n },\n async listVersions(name) {\n await ready;\n return (await db.select().from(skillVersions).where(eq(skillVersions.name, name)).orderBy(desc(skillVersions.version))).map(toVersion);\n },\n async getVersion(name, version) {\n await ready;\n const [row] = await db.select().from(skillVersions).where(and(eq(skillVersions.name, name), eq(skillVersions.version, version)));\n return row ? toVersion(row) : null;\n },\n async recordLoad(load) {\n await ready;\n await db.insert(skillLoads).values({ ...load, loadedAt: new Date(load.loadedAt) });\n },\n async loadStats(name, limit) {\n await ready;\n const [{ total } = { total: 0 }] = await db.select({ total: count() }).from(skillLoads).where(eq(skillLoads.name, name));\n const recent = await db.select().from(skillLoads).where(eq(skillLoads.name, name)).orderBy(desc(skillLoads.loadedAt), desc(skillLoads.id)).limit(limit);\n return { total, recent: recent.map(toLoad) };\n },\n async loadCounts() {\n await ready;\n const rows = await db.select({ name: skillLoads.name, total: count() }).from(skillLoads).groupBy(skillLoads.name);\n return Object.fromEntries(rows.map((row) => [row.name, row.total]));\n },\n };\n}\n","import { bigserial, index, integer, pgSchema, primaryKey, text, timestamp } from \"drizzle-orm/pg-core\";\nimport type { SkillStatus } from \"../types\";\n\n/** Та же схема базы, что у хранилища чатов: у приложения одна база и одна схема `agent_chat`. */\nconst agentChatSchema = pgSchema(\"agent_chat\");\n\nconst moment = (name: string) => timestamp(name, { mode: \"date\", precision: 3, withTimezone: true });\n\nexport const skills = agentChatSchema.table(\"skills\", {\n name: text(\"name\").primaryKey(),\n whenToUse: text(\"when_to_use\").notNull(),\n body: text(\"body\").notNull(),\n status: text(\"status\").$type<SkillStatus>().notNull(),\n version: integer(\"version\").notNull(),\n createdBy: text(\"created_by\").notNull(),\n createdAt: moment(\"created_at\").notNull(),\n updatedBy: text(\"updated_by\").notNull(),\n updatedAt: moment(\"updated_at\").notNull(),\n});\n\nexport const skillVersions = agentChatSchema.table(\n \"skill_versions\",\n {\n name: text(\"name\").notNull(),\n version: integer(\"version\").notNull(),\n whenToUse: text(\"when_to_use\").notNull(),\n body: text(\"body\").notNull(),\n author: text(\"author\").notNull(),\n createdAt: moment(\"created_at\").notNull(),\n },\n (table) => [primaryKey({ columns: [table.name, table.version] })],\n);\n\nexport const skillLoads = agentChatSchema.table(\n \"skill_loads\",\n {\n id: bigserial(\"id\", { mode: \"number\" }).primaryKey(),\n name: text(\"name\").notNull(),\n version: integer(\"version\").notNull(),\n chatId: text(\"chat_id\").notNull(),\n ownerId: text(\"owner_id\").notNull(),\n turnId: text(\"turn_id\").notNull(),\n loadedAt: moment(\"loaded_at\").notNull(),\n },\n (table) => [index(\"skill_loads_name_loaded_idx\").on(table.name, table.loadedAt)],\n);\n"],"mappings":"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","names":["text"]}
|
|
1
|
+
{"version":3,"sources":["../src/postgres.ts","../src/store/postgres.ts","../src/store/postgres-schema.ts"],"sourcesContent":["import { fileURLToPath } from \"node:url\";\nimport type { Pool } from \"pg\";\nimport type { SkillStore } from \"./types\";\nimport { createPostgresSkillStore } from \"./store/postgres\";\n\nexport { SKILLS_MIGRATION_LOCK_KEY, SKILLS_MIGRATIONS_TABLE } from \"./store/migration-settings\";\nexport { skillLoads, skills, skillVersions } from \"./store/postgres-schema\";\n\n/** Миграции лежат в пакете рядом с `dist`: `drizzle/postgres`. */\nconst MIGRATIONS_FOLDER = fileURLToPath(new URL(\"../drizzle/postgres\", import.meta.url));\n\n/**\n * Навыки в PostgreSQL на пуле приложения (схема `agent_chat`, та же база, что у хранилища чатов).\n * Таблицы приводятся к последней миграции при первом обращении. Пул закрывает приложение.\n */\nexport function postgresSkillStore(pool: Pool): SkillStore {\n return createPostgresSkillStore(pool, MIGRATIONS_FOLDER);\n}\n","import { and, count, desc, eq, getTableColumns } from \"drizzle-orm\";\nimport { drizzle } from \"drizzle-orm/node-postgres\";\nimport { migrate } from \"drizzle-orm/node-postgres/migrator\";\nimport { migratePostgresSchema } from \"@ykurilov/agent-chat-core\";\nimport type { Pool } from \"pg\";\nimport { SkillExistsError, SkillNotFoundError, SkillVersionConflictError } from \"../types\";\nimport type { Skill, SkillBrief, SkillLoad, SkillStore, SkillVersion } from \"../types\";\nimport { SKILLS_MIGRATION_LOCK_KEY, SKILLS_MIGRATIONS_TABLE } from \"./migration-settings\";\nimport { skillLoads, skills, skillVersions } from \"./postgres-schema\";\nimport { byName, sameText, storedText } from \"./skill-store\";\n\nfunction toSkill(row: typeof skills.$inferSelect): Skill {\n return { ...row, createdAt: row.createdAt.toISOString(), updatedAt: row.updatedAt.toISOString() };\n}\n\nconst { body: _body, ...briefColumns } = getTableColumns(skills);\n\nfunction toBrief(row: Omit<typeof skills.$inferSelect, \"body\">): SkillBrief {\n return { ...row, createdAt: row.createdAt.toISOString(), updatedAt: row.updatedAt.toISOString() };\n}\n\nfunction toVersion(row: typeof skillVersions.$inferSelect): SkillVersion {\n return { ...row, createdAt: row.createdAt.toISOString() };\n}\n\nfunction toLoad({ id: _id, ...row }: typeof skillLoads.$inferSelect): SkillLoad {\n return { ...row, loadedAt: row.loadedAt.toISOString() };\n}\n\n/**\n * Приводит таблицы навыков к последней миграции. Схема `agent_chat` создаётся под общей блокировкой всех пакетов, миграции — под своей:\n * копии пакета ждут друг друга, а разные пакеты стартуют разом на пустой базе без гонки за схему.\n */\nexport async function migrateSkillsToLatest(pool: Pool, migrationsFolder: string): Promise<void> {\n await migratePostgresSchema({\n connect: () => pool.connect(),\n lockKey: SKILLS_MIGRATION_LOCK_KEY,\n migrate: (client) => migrate(drizzle(client), { migrationsFolder, migrationsSchema: \"agent_chat\", migrationsTable: SKILLS_MIGRATIONS_TABLE }),\n });\n}\n\n/**\n * Навыки в PostgreSQL (схема `agent_chat`) на пуле приложения. Миграция идёт при первом обращении, каждая операция\n * её дожидается. Правка и её версия — в одной транзакции с условием на номер версии. Пул закрывает приложение.\n */\nexport function createPostgresSkillStore(pool: Pool, migrationsFolder: string): SkillStore {\n const db = drizzle(pool);\n const ready = migrateSkillsToLatest(pool, migrationsFolder);\n // Ошибка миграции придёт в каждую операцию; без этого она всплыла бы ещё и как необработанная.\n ready.catch(() => {});\n\n async function get(name: string): Promise<Skill | null> {\n await ready;\n const [row] = await db.select().from(skills).where(eq(skills.name, name));\n return row ? toSkill(row) : null;\n }\n\n return {\n async list() {\n await ready;\n return (await db.select().from(skills)).map(toSkill).sort(byName);\n },\n async listBrief() {\n await ready;\n return (await db.select(briefColumns).from(skills)).map(toBrief).sort(byName);\n },\n get,\n async create(input, at) {\n await ready;\n const text = storedText(input);\n return db.transaction(async (tx) => {\n const [row] = await tx\n .insert(skills)\n .values({ name: input.name, ...text, status: input.status, version: 1, createdBy: input.author, createdAt: new Date(at), updatedBy: input.author, updatedAt: new Date(at) })\n .onConflictDoNothing()\n .returning();\n if (!row) throw new SkillExistsError(input.name);\n await tx.insert(skillVersions).values({ name: input.name, version: 1, ...text, author: input.author, createdAt: new Date(at) });\n return toSkill(row);\n });\n },\n async updateText(name, edit, at) {\n await ready;\n const text = storedText(edit);\n return db.transaction(async (tx) => {\n const [current] = await tx.select().from(skills).where(eq(skills.name, name));\n if (!current) throw new SkillNotFoundError(name);\n if (current.version !== edit.expectedVersion) throw new SkillVersionConflictError(name, current.version);\n if (sameText(toSkill(current), text)) return toSkill(current);\n const version = current.version + 1;\n // Условие на версию — в том же `update … where`: соперник, успевший первым, оставит здесь ноль строк.\n const [row] = await tx\n .update(skills)\n .set({ ...text, version, updatedBy: edit.author, updatedAt: new Date(at) })\n .where(and(eq(skills.name, name), eq(skills.version, edit.expectedVersion)))\n .returning();\n if (!row) {\n const [latest] = await db.select({ version: skills.version }).from(skills).where(eq(skills.name, name));\n if (!latest) throw new SkillNotFoundError(name);\n throw new SkillVersionConflictError(name, latest.version);\n }\n await tx.insert(skillVersions).values({ name, version, ...text, author: edit.author, createdAt: new Date(at) });\n return toSkill(row);\n });\n },\n async setStatus(name, status, author, at) {\n await ready;\n const [row] = await db.update(skills).set({ status, updatedBy: author, updatedAt: new Date(at) }).where(eq(skills.name, name)).returning();\n if (!row) throw new SkillNotFoundError(name);\n return toSkill(row);\n },\n async delete(name) {\n await ready;\n return db.transaction(async (tx) => {\n await tx.delete(skillLoads).where(eq(skillLoads.name, name));\n await tx.delete(skillVersions).where(eq(skillVersions.name, name));\n const removed = await tx.delete(skills).where(eq(skills.name, name)).returning({ name: skills.name });\n return removed.length > 0;\n });\n },\n async listVersions(name) {\n await ready;\n return (await db.select().from(skillVersions).where(eq(skillVersions.name, name)).orderBy(desc(skillVersions.version))).map(toVersion);\n },\n async getVersion(name, version) {\n await ready;\n const [row] = await db.select().from(skillVersions).where(and(eq(skillVersions.name, name), eq(skillVersions.version, version)));\n return row ? toVersion(row) : null;\n },\n async recordLoad(load) {\n await ready;\n await db.insert(skillLoads).values({ ...load, loadedAt: new Date(load.loadedAt) });\n },\n async loadStats(name, limit) {\n await ready;\n const [{ total } = { total: 0 }] = await db.select({ total: count() }).from(skillLoads).where(eq(skillLoads.name, name));\n const recent = await db.select().from(skillLoads).where(eq(skillLoads.name, name)).orderBy(desc(skillLoads.loadedAt), desc(skillLoads.id)).limit(limit);\n return { total, recent: recent.map(toLoad) };\n },\n async loadCounts() {\n await ready;\n const rows = await db.select({ name: skillLoads.name, total: count() }).from(skillLoads).groupBy(skillLoads.name);\n return Object.fromEntries(rows.map((row) => [row.name, row.total]));\n },\n };\n}\n","import { bigserial, index, integer, pgSchema, primaryKey, text, timestamp } from \"drizzle-orm/pg-core\";\nimport type { SkillStatus } from \"../types\";\n\n/** Та же схема базы, что у хранилища чатов: у приложения одна база и одна схема `agent_chat`. */\nconst agentChatSchema = pgSchema(\"agent_chat\");\n\nconst moment = (name: string) => timestamp(name, { mode: \"date\", precision: 3, withTimezone: true });\n\nexport const skills = agentChatSchema.table(\"skills\", {\n name: text(\"name\").primaryKey(),\n whenToUse: text(\"when_to_use\").notNull(),\n body: text(\"body\").notNull(),\n status: text(\"status\").$type<SkillStatus>().notNull(),\n version: integer(\"version\").notNull(),\n createdBy: text(\"created_by\").notNull(),\n createdAt: moment(\"created_at\").notNull(),\n updatedBy: text(\"updated_by\").notNull(),\n updatedAt: moment(\"updated_at\").notNull(),\n});\n\nexport const skillVersions = agentChatSchema.table(\n \"skill_versions\",\n {\n name: text(\"name\").notNull(),\n version: integer(\"version\").notNull(),\n whenToUse: text(\"when_to_use\").notNull(),\n body: text(\"body\").notNull(),\n author: text(\"author\").notNull(),\n createdAt: moment(\"created_at\").notNull(),\n },\n (table) => [primaryKey({ columns: [table.name, table.version] })],\n);\n\nexport const skillLoads = agentChatSchema.table(\n \"skill_loads\",\n {\n id: bigserial(\"id\", { mode: \"number\" }).primaryKey(),\n name: text(\"name\").notNull(),\n version: integer(\"version\").notNull(),\n chatId: text(\"chat_id\").notNull(),\n ownerId: text(\"owner_id\").notNull(),\n turnId: text(\"turn_id\").notNull(),\n loadedAt: moment(\"loaded_at\").notNull(),\n },\n (table) => [index(\"skill_loads_name_loaded_idx\").on(table.name, table.loadedAt)],\n);\n"],"mappings":"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","names":["text"]}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { Pool } from "pg";
|
|
2
2
|
import type { SkillStore } from "../types.js";
|
|
3
3
|
/**
|
|
4
|
-
* Приводит таблицы навыков к последней миграции.
|
|
5
|
-
*
|
|
4
|
+
* Приводит таблицы навыков к последней миграции. Схема `agent_chat` создаётся под общей блокировкой всех пакетов, миграции — под своей:
|
|
5
|
+
* копии пакета ждут друг друга, а разные пакеты стартуют разом на пустой базе без гонки за схему.
|
|
6
6
|
*/
|
|
7
7
|
export declare function migrateSkillsToLatest(pool: Pool, migrationsFolder: string): Promise<void>;
|
|
8
8
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ykurilov/agent-chat-skills",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.58.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"ai": "7.0.122",
|
|
54
54
|
"drizzle-orm": "^0.45.3",
|
|
55
55
|
"zod": "^4.6.5",
|
|
56
|
-
"@ykurilov/agent-chat-core": "0.
|
|
56
|
+
"@ykurilov/agent-chat-core": "0.58.0"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"better-sqlite3": "^13.0.3",
|