@smwb/onreel-git-mcp 0.9.0 → 0.10.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/README.md +80 -6
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/kernel/store.types.d.ts +16 -2
- package/dist/tracker/github-repo.lib.d.ts +2 -0
- package/dist/tracker/gitlab-repo.lib.d.ts +2 -0
- package/dist/tracker/index.d.ts +6 -0
- package/dist/tracker/index.js +287 -42
- package/dist/tracker/index.js.map +1 -1
- package/dist/tracker/repo.lib.d.ts +4 -0
- package/dist/tracker/repo.schema.d.ts +35 -0
- package/dist/tracker/repo.types.d.ts +20 -0
- package/dist/tracker/sourcecraft-repo.lib.d.ts +2 -0
- package/dist/tracker/tracker.types.d.ts +4 -1
- package/dist/worktree/index.js +1 -1
- package/dist/worktree/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { RepoAdapter } from './repo.types.ts';
|
|
2
|
+
import type { AdapterContext, TrackerDefinition } from './tracker.types.ts';
|
|
3
|
+
/** Адаптер репозитория трекера (D-008); трекер без раздела repo — TrackerError('unsupported', 'Трекер <title> не ведёт репозиторий.'). */
|
|
4
|
+
export declare function repoAdapterOf(definition: TrackerDefinition, context: AdapterContext): RepoAdapter;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/** Видимость репозитория единой модели (#23): GitHub, GitLab и SourceCraft называют её одними словами. */
|
|
3
|
+
export declare const repoVisibilitySchema: z.ZodEnum<{
|
|
4
|
+
internal: "internal";
|
|
5
|
+
private: "private";
|
|
6
|
+
public: "public";
|
|
7
|
+
}>;
|
|
8
|
+
/** Фильтры списка веток — имена полей BranchQuery. */
|
|
9
|
+
export declare const branchFilterSchema: z.ZodEnum<{
|
|
10
|
+
search: "search";
|
|
11
|
+
}>;
|
|
12
|
+
export declare const repoSchema: z.ZodObject<{
|
|
13
|
+
name: z.ZodString;
|
|
14
|
+
defaultBranch: z.ZodOptional<z.ZodString>;
|
|
15
|
+
description: z.ZodOptional<z.ZodString>;
|
|
16
|
+
visibility: z.ZodOptional<z.ZodEnum<{
|
|
17
|
+
internal: "internal";
|
|
18
|
+
private: "private";
|
|
19
|
+
public: "public";
|
|
20
|
+
}>>;
|
|
21
|
+
links: z.ZodArray<z.ZodObject<{
|
|
22
|
+
url: z.ZodString;
|
|
23
|
+
title: z.ZodOptional<z.ZodString>;
|
|
24
|
+
}, z.core.$strip>>;
|
|
25
|
+
}, z.core.$strip>;
|
|
26
|
+
export declare const branchSchema: z.ZodObject<{
|
|
27
|
+
name: z.ZodString;
|
|
28
|
+
sha: z.ZodOptional<z.ZodString>;
|
|
29
|
+
protected: z.ZodOptional<z.ZodBoolean>;
|
|
30
|
+
isDefault: z.ZodOptional<z.ZodBoolean>;
|
|
31
|
+
}, z.core.$strip>;
|
|
32
|
+
export type RepoVisibility = z.infer<typeof repoVisibilitySchema>;
|
|
33
|
+
export type BranchFilter = z.infer<typeof branchFilterSchema>;
|
|
34
|
+
export type Repo = z.infer<typeof repoSchema>;
|
|
35
|
+
export type Branch = z.infer<typeof branchSchema>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Branch, BranchFilter, Repo } from './repo.schema.ts';
|
|
2
|
+
import type { AdapterContext, ListCapabilities, PageQuery, TrackerPage } from './tracker.types.ts';
|
|
3
|
+
export type BranchQuery = PageQuery & {
|
|
4
|
+
/** Подстрока имени ветки: GitLab и SourceCraft фильтруют сервером, GitHub — по полученной странице. */
|
|
5
|
+
search?: string | undefined;
|
|
6
|
+
};
|
|
7
|
+
/** Карточка репозитория и ветки git-хостинга того же подключения. */
|
|
8
|
+
export type RepoAdapter = {
|
|
9
|
+
get(): Promise<Repo>;
|
|
10
|
+
branches(query: BranchQuery): Promise<TrackerPage<Branch>>;
|
|
11
|
+
};
|
|
12
|
+
/** Возможности раздела repo: список веток описан как другие списки (D-004); сортировки веток нет. */
|
|
13
|
+
export type RepoCapabilities = {
|
|
14
|
+
branches: ListCapabilities<BranchFilter, never>;
|
|
15
|
+
};
|
|
16
|
+
/** Раздел repo определения трекера (D-008): на том же подключении, что и задачи. */
|
|
17
|
+
export type RepoDefinition = {
|
|
18
|
+
capabilities: RepoCapabilities;
|
|
19
|
+
create(context: AdapterContext): RepoAdapter;
|
|
20
|
+
};
|
|
@@ -2,6 +2,7 @@ import type { Issue, IssueComment, IssuePriority, IssueStatusCategory, TrackerDe
|
|
|
2
2
|
import type { LocalIssueStore } from '../kernel/store.types.ts';
|
|
3
3
|
import type { CiDefinition } from './ci.types.ts';
|
|
4
4
|
import type { PullRequestDefinition } from './pull.types.ts';
|
|
5
|
+
import type { RepoDefinition } from './repo.types.ts';
|
|
5
6
|
import type { CommentFilter, IssueFilter, IssueSortField } from './tracker.const.ts';
|
|
6
7
|
/**
|
|
7
8
|
* fetch контекста. requestJson и requestText передают redirect: 'manual' и проходят редиректы сами: обёртка
|
|
@@ -125,8 +126,10 @@ export type TrackerDefinition = {
|
|
|
125
126
|
pulls?: PullRequestDefinition | undefined;
|
|
126
127
|
/** CI трекера на том же подключении (D-005); нет — ciAdapterOf отказывает unsupported. */
|
|
127
128
|
ci?: CiDefinition | undefined;
|
|
129
|
+
/** Репозиторий git-хостинга на том же подключении (D-008); нет — repoAdapterOf отказывает unsupported. */
|
|
130
|
+
repo?: RepoDefinition | undefined;
|
|
128
131
|
/**
|
|
129
|
-
* Origin API, к которому адаптер (и его разделы pulls и
|
|
132
|
+
* Origin API, к которому адаптер (и его разделы pulls, ci и repo) обращается с токеном подключения, например
|
|
130
133
|
* https://api.github.com. Потребитель привязывает к нему токен: правка url на другой origin — повод спросить
|
|
131
134
|
* токен заново. Неверное подключение — TrackerError, как у create. Нет — трекер не объявил origin (у local
|
|
132
135
|
* сети и токена нет).
|
package/dist/worktree/index.js
CHANGED
|
@@ -127,7 +127,7 @@ async function releaseGitState(services, worktree, ownsBranch) {
|
|
|
127
127
|
function reconcileWorktreesAtStart(services) {
|
|
128
128
|
for (const worktree of services.store.worktreesInStatus(["preparing"])) {
|
|
129
129
|
services.store.inTransaction((tx) => {
|
|
130
|
-
tx.markWorktreeFailed(worktree.id, "
|
|
130
|
+
tx.markWorktreeFailed(worktree.id, "\u043F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B\u044C \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0449\u0435\u043D \u0432\u043E \u0432\u0440\u0435\u043C\u044F \u0441\u043E\u0437\u0434\u0430\u043D\u0438\u044F worktree", { actor: HOST_ACTOR });
|
|
131
131
|
tx.requestWorktreeCleanup(worktree.id, { actor: HOST_ACTOR, discardChanges: true, evidence: "\u043E\u0447\u0438\u0441\u0442\u043A\u0430 \u043F\u043E\u0441\u043B\u0435 \u043F\u0440\u0435\u0440\u0432\u0430\u043D\u043D\u043E\u0433\u043E \u0441\u043E\u0437\u0434\u0430\u043D\u0438\u044F" });
|
|
132
132
|
});
|
|
133
133
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/worktree/lifecycle.const.ts","../../src/worktree/lifecycle.lib.ts"],"sourcesContent":["// Происхождение — onreel @ b73407be076a5df73931d1340f70910ca13c908d,\n// src/host/worktree/lifecycle.const.ts — дословная копия.\n\n/** Период reconciler: подбирает worktree завершённых Task и прерванные очистки (§6.8). */\nexport const WORKTREE_RECONCILE_INTERVAL_MS = 30_000;\n","// Жизненный цикл worktree библиотеки @smwb/onreel-git-mcp (часть D выделения).\n// Происхождение — onreel @ b73407be076a5df73931d1340f70910ca13c908d,\n// src/host/worktree/lifecycle.lib.ts — 9 прямых вызовов функций ledger заменены на порт\n// WorktreeStore ядра (kernel/store.types.ts, D-003): чтения — методы порта, записи — только\n// внутри единицы работы store.inTransaction (соответствие 1:1, в том числе группировка\n// вызовов в одну транзакцию). Хранилище пишет потребитель, эталонная реализация в памяти —\n// в тестах библиотеки (test/helpers/memory-store.lib.ts).\nimport { randomUUID } from 'node:crypto';\nimport { mkdirSync, readdirSync, renameSync } from 'node:fs';\nimport { rm } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { Worktree } from '../contract/contract.types.ts';\nimport * as GitOps from '../git/git.lib.ts';\nimport { checkManagedPath, prepareWorktreeParent, trashRoot } from '../git/paths.lib.ts';\nimport { WORKTREE_RECONCILE_INTERVAL_MS } from './lifecycle.const.ts';\nimport type { WorktreeLifecycleServices, WorktreeReconciler } from './lifecycle.types.ts';\n\n// Вторая фаза создания и очистки worktree (D-050) и reconciler (§6.8, D-080). Receipt-транзакция\n// уже записала preparing или cleaning; здесь git и диск работают вне транзакции, а итог —\n// ready, cleaned или failed с причиной — пишется отдельной транзакцией. Работа над одним\n// worktree идёт под его замком: создание, очистка, коммит и rebase не перекрываются.\n\ntype Services = WorktreeLifecycleServices;\n\nconst HOST_ACTOR = 'host';\n\n// --- Замок на worktree ---\n\nconst locks = new Map<string, Promise<void>>();\n\n/** Берёт замок worktree: возвращает функцию освобождения. Ожидающие идут по очереди. */\nexport async function acquireWorktreeLock(id: string): Promise<() => void> {\n const previous = locks.get(id) ?? Promise.resolve();\n let release!: () => void;\n const current = new Promise<void>((resolve) => (release = resolve));\n const chained = previous.then(() => current);\n locks.set(id, chained);\n await previous;\n let released = false;\n return () => {\n if (released) return;\n released = true;\n release();\n if (locks.get(id) === chained) locks.delete(id);\n };\n}\n\nexport async function withWorktreeLock<T>(id: string, fn: () => Promise<T>): Promise<T> {\n const release = await acquireWorktreeLock(id);\n try {\n return await fn();\n } finally {\n release();\n }\n}\n\n/** Над worktree сейчас идёт работа этого процесса. */\nexport function isWorktreeBusy(id: string): boolean {\n return locks.has(id);\n}\n\n// --- Создание ---\n\n/**\n * Доводит preparing до ready: каталог под корнем workspaces, `git worktree add --no-track`,\n * HEAD. Сбой — failed с причиной и сразу очистка остатков (каталог и пустая ветка).\n */\nexport async function finishPreparing(services: Services, id: string): Promise<void> {\n await withWorktreeLock(id, async () => {\n const worktree = services.store.getWorktree(id);\n if (worktree?.status !== 'preparing') return;\n let headSha: string;\n let foreignBranch = false;\n try {\n prepareWorktreeParent(services.dataDir, worktree.path);\n // Ветка появилась после проверки create: она чужая, git -b откажет, очистка её не тронет.\n foreignBranch = (await GitOps.branchSha(worktree.repoPath, worktree.branch)) !== undefined;\n await GitOps.addWorktree(worktree.repoPath, worktree.path, worktree.branch, worktree.baseSha);\n headSha = await GitOps.headOf(worktree.path);\n } catch (error) {\n // Остановка потребителя: preparing доведёт сверка при следующем старте.\n if (GitOps.isGitPoolClosed()) return;\n services.store.inTransaction((tx) => {\n tx.markWorktreeFailed(id, `создание не удалось: ${messageOf(error)}`, { actor: HOST_ACTOR });\n // Работы в незавершённом worktree нет: остатки убираются без проверки изменений.\n tx.requestWorktreeCleanup(id, { actor: HOST_ACTOR, discardChanges: true, foreignBranch, evidence: 'очистка после неудачного создания' });\n });\n await cleanUnderLock(services, id);\n return;\n }\n services.store.inTransaction((tx) => tx.markWorktreeReady(id, headSha, { actor: HOST_ACTOR }));\n });\n}\n\n// --- Очистка ---\n\n/** Доводит cleaning до cleaned (или failed с причиной) под замком worktree. */\nexport async function finishCleaning(services: Services, id: string): Promise<void> {\n await withWorktreeLock(id, () => cleanUnderLock(services, id));\n}\n\n/**\n * Очистка (D-079, D-088): незакоммиченные изменения без решения вызывающего — failed, каталог\n * остаётся; иначе каталог переносится в trash, git снимает worktree с учёта, ветка без\n * коммитов сверх базы удаляется, trash удаляется. Перенос не удался — failed с причиной.\n */\nasync function cleanUnderLock(services: Services, id: string): Promise<void> {\n const worktree = services.store.getWorktree(id);\n if (worktree?.status !== 'cleaning') return;\n let trashed: string | undefined;\n let flags: { discardChanges: boolean; ownsBranch: boolean };\n try {\n const present = checkManagedPath(services.dataDir, worktree.path);\n flags = services.store.worktreeCleanupFlags(id);\n if (present && !flags.discardChanges && (await GitOps.isDirty(worktree.path))) {\n services.store.inTransaction((tx) =>\n tx.markWorktreeFailed(id, 'в worktree незакоммиченные изменения: очистка ждёт решения (worktree.remove с force: true выбросит их)', {\n actor: HOST_ACTOR,\n }),\n );\n return;\n }\n if (present) {\n const trash = trashRoot(services.dataDir);\n mkdirSync(trash, { recursive: true, mode: 0o700 });\n trashed = join(trash, `${worktree.id}-${randomUUID()}`);\n renameSync(worktree.path, trashed);\n }\n } catch (error) {\n // Остановка потребителя: cleaning доведёт reconciler при следующем старте.\n if (GitOps.isGitPoolClosed()) return;\n services.store.inTransaction((tx) => tx.markWorktreeFailed(id, `очистка не удалась: ${messageOf(error)}`, { actor: HOST_ACTOR }));\n return;\n }\n // Каталог ушёл с места: дальнейшие сбои не возвращают worktree — они в журнал, а trash\n // доочищается при старте (§6.9: прерванные удаления завершаются при старте).\n await releaseGitState(services, worktree, flags.ownsBranch);\n if (GitOps.isGitPoolClosed()) return;\n if (trashed !== undefined) {\n await rm(trashed, { recursive: true, force: true }).catch((error: unknown) => {\n services.log(`worktree ${worktree.id}: trash ${trashed ?? ''} не удалён: ${messageOf(error)}`);\n });\n }\n services.store.inTransaction((tx) => tx.completeWorktreeCleanup(id, { actor: HOST_ACTOR }));\n}\n\n/** Снимает worktree с учёта репозитория и удаляет ветку host, если на ней нет работы (tip = база). */\nasync function releaseGitState(services: Services, worktree: Worktree, ownsBranch: boolean): Promise<void> {\n try {\n await GitOps.pruneWorktrees(worktree.repoPath);\n if (!ownsBranch) return;\n const tip = await GitOps.branchSha(worktree.repoPath, worktree.branch);\n if (tip !== undefined && tip === worktree.baseSha) await GitOps.deleteBranch(worktree.repoPath, worktree.branch);\n } catch (error) {\n services.log(`worktree ${worktree.id}: репозиторий ${worktree.repoPath} не обновлён после очистки: ${messageOf(error)}`);\n }\n}\n\n// --- Reconciler ---\n\n/**\n * Сверка при старте, синхронно до приёма запросов: preparing без процесса, который его вёл,\n * — failed (потребитель упал посреди создания) и сразу в очистку. Дальше работает sweep.\n */\nexport function reconcileWorktreesAtStart(services: Services): void {\n for (const worktree of services.store.worktreesInStatus(['preparing'])) {\n services.store.inTransaction((tx) => {\n tx.markWorktreeFailed(worktree.id, 'host перезапущен во время создания worktree', { actor: HOST_ACTOR });\n tx.requestWorktreeCleanup(worktree.id, { actor: HOST_ACTOR, discardChanges: true, evidence: 'очистка после прерванного создания' });\n });\n }\n}\n\n/**\n * Один проход reconciler: ready worktree завершённых Task — в cleaning, все cleaning без\n * работы в этом процессе — до cleaned или failed. failed остаётся до решения (worktree.remove).\n */\nexport async function sweepWorktrees(services: Services): Promise<void> {\n for (const worktree of services.store.readyWorktreesOfSettledTasks()) {\n if (isWorktreeBusy(worktree.id)) continue;\n try {\n services.store.inTransaction((tx) => tx.requestWorktreeCleanup(worktree.id, { actor: HOST_ACTOR, evidence: 'Task завершена' }));\n } catch (error) {\n services.log(`worktree ${worktree.id}: очистка после завершения Task не началась: ${messageOf(error)}`);\n }\n }\n for (const worktree of services.store.worktreesInStatus(['cleaning'])) {\n if (isWorktreeBusy(worktree.id)) continue;\n await finishCleaning(services, worktree.id);\n }\n}\n\n/** Доочищает trash, брошенный прерванными удалениями. */\nexport async function emptyTrash(services: Services): Promise<void> {\n const trash = trashRoot(services.dataDir);\n let entries: string[];\n try {\n entries = readdirSync(trash);\n } catch {\n return;\n }\n for (const entry of entries) {\n await rm(join(trash, entry), { recursive: true, force: true }).catch((error: unknown) => {\n services.log(`trash ${entry} не удалён: ${messageOf(error)}`);\n });\n }\n}\n\n/** Запускает reconciler: сверка при старте, затем проход сразу и по таймеру. */\nexport function startWorktreeReconciler(services: Services, intervalMs = WORKTREE_RECONCILE_INTERVAL_MS): WorktreeReconciler {\n reconcileWorktreesAtStart(services);\n let current: Promise<void> = Promise.resolve();\n let stopped = false;\n const kick = (): Promise<void> => {\n if (stopped) return current;\n current = current.then(() => sweepWorktrees(services)).catch((error: unknown) => {\n services.log(`reconciler worktree: проход не удался: ${messageOf(error)}`);\n });\n return current;\n };\n current = emptyTrash(services);\n void kick();\n const timer = setInterval(() => void kick(), intervalMs);\n timer.unref();\n return {\n kick,\n stop: async () => {\n stopped = true;\n clearInterval(timer);\n await current;\n },\n };\n}\n\nexport function messageOf(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAIO,IAAM,iCAAiC;;;ACG9C,SAAS,kBAAkB;AAC3B,SAAS,WAAW,aAAa,kBAAkB;AACnD,SAAS,UAAU;AACnB,SAAS,YAAY;AAcrB,IAAM,aAAa;AAInB,IAAM,QAAQ,oBAAI,IAA2B;AAG7C,eAAsB,oBAAoB,IAAiC;AACzE,QAAM,WAAW,MAAM,IAAI,EAAE,KAAK,QAAQ,QAAQ;AAClD,MAAI;AACJ,QAAM,UAAU,IAAI,QAAc,CAAC,YAAa,UAAU,OAAQ;AAClE,QAAM,UAAU,SAAS,KAAK,MAAM,OAAO;AAC3C,QAAM,IAAI,IAAI,OAAO;AACrB,QAAM;AACN,MAAI,WAAW;AACf,SAAO,MAAM;AACX,QAAI,SAAU;AACd,eAAW;AACX,YAAQ;AACR,QAAI,MAAM,IAAI,EAAE,MAAM,QAAS,OAAM,OAAO,EAAE;AAAA,EAChD;AACF;AAEA,eAAsB,iBAAoB,IAAY,IAAkC;AACtF,QAAM,UAAU,MAAM,oBAAoB,EAAE;AAC5C,MAAI;AACF,WAAO,MAAM,GAAG;AAAA,EAClB,UAAE;AACA,YAAQ;AAAA,EACV;AACF;AAGO,SAAS,eAAe,IAAqB;AAClD,SAAO,MAAM,IAAI,EAAE;AACrB;AAQA,eAAsB,gBAAgB,UAAoB,IAA2B;AACnF,QAAM,iBAAiB,IAAI,YAAY;AACrC,UAAM,WAAW,SAAS,MAAM,YAAY,EAAE;AAC9C,QAAI,UAAU,WAAW,YAAa;AACtC,QAAI;AACJ,QAAI,gBAAgB;AACpB,QAAI;AACF,4BAAsB,SAAS,SAAS,SAAS,IAAI;AAErD,sBAAiB,MAAa,UAAU,SAAS,UAAU,SAAS,MAAM,MAAO;AACjF,YAAa,YAAY,SAAS,UAAU,SAAS,MAAM,SAAS,QAAQ,SAAS,OAAO;AAC5F,gBAAU,MAAa,OAAO,SAAS,IAAI;AAAA,IAC7C,SAAS,OAAO;AAEd,UAAW,gBAAgB,EAAG;AAC9B,eAAS,MAAM,cAAc,CAAC,OAAO;AACnC,WAAG,mBAAmB,IAAI,6GAAwB,UAAU,KAAK,CAAC,IAAI,EAAE,OAAO,WAAW,CAAC;AAE3F,WAAG,uBAAuB,IAAI,EAAE,OAAO,YAAY,gBAAgB,MAAM,eAAe,UAAU,0LAAoC,CAAC;AAAA,MACzI,CAAC;AACD,YAAM,eAAe,UAAU,EAAE;AACjC;AAAA,IACF;AACA,aAAS,MAAM,cAAc,CAAC,OAAO,GAAG,kBAAkB,IAAI,SAAS,EAAE,OAAO,WAAW,CAAC,CAAC;AAAA,EAC/F,CAAC;AACH;AAKA,eAAsB,eAAe,UAAoB,IAA2B;AAClF,QAAM,iBAAiB,IAAI,MAAM,eAAe,UAAU,EAAE,CAAC;AAC/D;AAOA,eAAe,eAAe,UAAoB,IAA2B;AAC3E,QAAM,WAAW,SAAS,MAAM,YAAY,EAAE;AAC9C,MAAI,UAAU,WAAW,WAAY;AACrC,MAAI;AACJ,MAAI;AACJ,MAAI;AACF,UAAM,UAAU,iBAAiB,SAAS,SAAS,SAAS,IAAI;AAChE,YAAQ,SAAS,MAAM,qBAAqB,EAAE;AAC9C,QAAI,WAAW,CAAC,MAAM,kBAAmB,MAAa,QAAQ,SAAS,IAAI,GAAI;AAC7E,eAAS,MAAM;AAAA,QAAc,CAAC,OAC5B,GAAG,mBAAmB,IAAI,wXAA0G;AAAA,UAClI,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AACA;AAAA,IACF;AACA,QAAI,SAAS;AACX,YAAM,QAAQ,UAAU,SAAS,OAAO;AACxC,gBAAU,OAAO,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AACjD,gBAAU,KAAK,OAAO,GAAG,SAAS,EAAE,IAAI,WAAW,CAAC,EAAE;AACtD,iBAAW,SAAS,MAAM,OAAO;AAAA,IACnC;AAAA,EACF,SAAS,OAAO;AAEd,QAAW,gBAAgB,EAAG;AAC9B,aAAS,MAAM,cAAc,CAAC,OAAO,GAAG,mBAAmB,IAAI,uGAAuB,UAAU,KAAK,CAAC,IAAI,EAAE,OAAO,WAAW,CAAC,CAAC;AAChI;AAAA,EACF;AAGA,QAAM,gBAAgB,UAAU,UAAU,MAAM,UAAU;AAC1D,MAAW,gBAAgB,EAAG;AAC9B,MAAI,YAAY,QAAW;AACzB,UAAM,GAAG,SAAS,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC,EAAE,MAAM,CAAC,UAAmB;AAC5E,eAAS,IAAI,YAAY,SAAS,EAAE,WAAW,WAAW,EAAE,uDAAe,UAAU,KAAK,CAAC,EAAE;AAAA,IAC/F,CAAC;AAAA,EACH;AACA,WAAS,MAAM,cAAc,CAAC,OAAO,GAAG,wBAAwB,IAAI,EAAE,OAAO,WAAW,CAAC,CAAC;AAC5F;AAGA,eAAe,gBAAgB,UAAoB,UAAoB,YAAoC;AACzG,MAAI;AACF,UAAa,eAAe,SAAS,QAAQ;AAC7C,QAAI,CAAC,WAAY;AACjB,UAAM,MAAM,MAAa,UAAU,SAAS,UAAU,SAAS,MAAM;AACrE,QAAI,QAAQ,UAAa,QAAQ,SAAS,QAAS,OAAa,aAAa,SAAS,UAAU,SAAS,MAAM;AAAA,EACjH,SAAS,OAAO;AACd,aAAS,IAAI,YAAY,SAAS,EAAE,wEAAiB,SAAS,QAAQ,6IAA+B,UAAU,KAAK,CAAC,EAAE;AAAA,EACzH;AACF;AAQO,SAAS,0BAA0B,UAA0B;AAClE,aAAW,YAAY,SAAS,MAAM,kBAAkB,CAAC,WAAW,CAAC,GAAG;AACtE,aAAS,MAAM,cAAc,CAAC,OAAO;AACnC,SAAG,mBAAmB,SAAS,IAAI,iLAA+C,EAAE,OAAO,WAAW,CAAC;AACvG,SAAG,uBAAuB,SAAS,IAAI,EAAE,OAAO,YAAY,gBAAgB,MAAM,UAAU,gMAAqC,CAAC;AAAA,IACpI,CAAC;AAAA,EACH;AACF;AAMA,eAAsB,eAAe,UAAmC;AACtE,aAAW,YAAY,SAAS,MAAM,6BAA6B,GAAG;AACpE,QAAI,eAAe,SAAS,EAAE,EAAG;AACjC,QAAI;AACF,eAAS,MAAM,cAAc,CAAC,OAAO,GAAG,uBAAuB,SAAS,IAAI,EAAE,OAAO,YAAY,UAAU,8DAAiB,CAAC,CAAC;AAAA,IAChI,SAAS,OAAO;AACd,eAAS,IAAI,YAAY,SAAS,EAAE,gNAAgD,UAAU,KAAK,CAAC,EAAE;AAAA,IACxG;AAAA,EACF;AACA,aAAW,YAAY,SAAS,MAAM,kBAAkB,CAAC,UAAU,CAAC,GAAG;AACrE,QAAI,eAAe,SAAS,EAAE,EAAG;AACjC,UAAM,eAAe,UAAU,SAAS,EAAE;AAAA,EAC5C;AACF;AAGA,eAAsB,WAAW,UAAmC;AAClE,QAAM,QAAQ,UAAU,SAAS,OAAO;AACxC,MAAI;AACJ,MAAI;AACF,cAAU,YAAY,KAAK;AAAA,EAC7B,QAAQ;AACN;AAAA,EACF;AACA,aAAW,SAAS,SAAS;AAC3B,UAAM,GAAG,KAAK,OAAO,KAAK,GAAG,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC,EAAE,MAAM,CAAC,UAAmB;AACvF,eAAS,IAAI,SAAS,KAAK,uDAAe,UAAU,KAAK,CAAC,EAAE;AAAA,IAC9D,CAAC;AAAA,EACH;AACF;AAGO,SAAS,wBAAwB,UAAoB,aAAa,gCAAoD;AAC3H,4BAA0B,QAAQ;AAClC,MAAI,UAAyB,QAAQ,QAAQ;AAC7C,MAAI,UAAU;AACd,QAAM,OAAO,MAAqB;AAChC,QAAI,QAAS,QAAO;AACpB,cAAU,QAAQ,KAAK,MAAM,eAAe,QAAQ,CAAC,EAAE,MAAM,CAAC,UAAmB;AAC/E,eAAS,IAAI,gHAA0C,UAAU,KAAK,CAAC,EAAE;AAAA,IAC3E,CAAC;AACD,WAAO;AAAA,EACT;AACA,YAAU,WAAW,QAAQ;AAC7B,OAAK,KAAK;AACV,QAAM,QAAQ,YAAY,MAAM,KAAK,KAAK,GAAG,UAAU;AACvD,QAAM,MAAM;AACZ,SAAO;AAAA,IACL;AAAA,IACA,MAAM,YAAY;AAChB,gBAAU;AACV,oBAAc,KAAK;AACnB,YAAM;AAAA,IACR;AAAA,EACF;AACF;AAEO,SAAS,UAAU,OAAwB;AAChD,SAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC9D;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/worktree/lifecycle.const.ts","../../src/worktree/lifecycle.lib.ts"],"sourcesContent":["// Происхождение — onreel @ b73407be076a5df73931d1340f70910ca13c908d,\n// src/host/worktree/lifecycle.const.ts — дословная копия.\n\n/** Период reconciler: подбирает worktree завершённых Task и прерванные очистки (§6.8). */\nexport const WORKTREE_RECONCILE_INTERVAL_MS = 30_000;\n","// Жизненный цикл worktree библиотеки @smwb/onreel-git-mcp (часть D выделения).\n// Происхождение — onreel @ b73407be076a5df73931d1340f70910ca13c908d,\n// src/host/worktree/lifecycle.lib.ts — 9 прямых вызовов функций ledger заменены на порт\n// WorktreeStore ядра (kernel/store.types.ts, D-003): чтения — методы порта, записи — только\n// внутри единицы работы store.inTransaction (соответствие 1:1, в том числе группировка\n// вызовов в одну транзакцию). Хранилище пишет потребитель, эталонная реализация в памяти —\n// в тестах библиотеки (test/helpers/memory-store.lib.ts).\nimport { randomUUID } from 'node:crypto';\nimport { mkdirSync, readdirSync, renameSync } from 'node:fs';\nimport { rm } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { Worktree } from '../contract/contract.types.ts';\nimport * as GitOps from '../git/git.lib.ts';\nimport { checkManagedPath, prepareWorktreeParent, trashRoot } from '../git/paths.lib.ts';\nimport { WORKTREE_RECONCILE_INTERVAL_MS } from './lifecycle.const.ts';\nimport type { WorktreeLifecycleServices, WorktreeReconciler } from './lifecycle.types.ts';\n\n// Вторая фаза создания и очистки worktree (D-050) и reconciler (§6.8, D-080). Receipt-транзакция\n// уже записала preparing или cleaning; здесь git и диск работают вне транзакции, а итог —\n// ready, cleaned или failed с причиной — пишется отдельной транзакцией. Работа над одним\n// worktree идёт под его замком: создание, очистка, коммит и rebase не перекрываются.\n\ntype Services = WorktreeLifecycleServices;\n\n// Актер собственных переходов библиотеки — процесс, который её держит (D-012). Значение уходит\n// в хранилище потребителя, то есть это данные, а не формулировка: потребитель отображает его\n// в свою лексику уже в реализации WorktreeStore.\nconst HOST_ACTOR = 'host';\n\n// --- Замок на worktree ---\n\n// Таблица замков одна на процесс и принадлежит этому модулю. Импортировать жизненный цикл из\n// нескольких точек входа можно: модуль двух и более точек входа tsup выносит в общий chunk, и\n// определение таблицы в бандле остаётся одно (D-013). Свою копию таблицы заводит только сборка\n// без splitting — тогда isWorktreeBusy перестаёт видеть работу, идущую через другой субпуть.\n// Инвариант держит test/worktree/locks-bundle.test.ts: он считает определения в собранном пакете.\nconst locks = new Map<string, Promise<void>>();\n\n/** Берёт замок worktree: возвращает функцию освобождения. Ожидающие идут по очереди. */\nexport async function acquireWorktreeLock(id: string): Promise<() => void> {\n const previous = locks.get(id) ?? Promise.resolve();\n let release!: () => void;\n const current = new Promise<void>((resolve) => (release = resolve));\n const chained = previous.then(() => current);\n locks.set(id, chained);\n await previous;\n let released = false;\n return () => {\n if (released) return;\n released = true;\n release();\n if (locks.get(id) === chained) locks.delete(id);\n };\n}\n\nexport async function withWorktreeLock<T>(id: string, fn: () => Promise<T>): Promise<T> {\n const release = await acquireWorktreeLock(id);\n try {\n return await fn();\n } finally {\n release();\n }\n}\n\n/** Над worktree сейчас идёт работа этого процесса. */\nexport function isWorktreeBusy(id: string): boolean {\n return locks.has(id);\n}\n\n// --- Создание ---\n\n/**\n * Доводит preparing до ready: каталог под корнем workspaces, `git worktree add --no-track`,\n * HEAD. Сбой — failed с причиной и сразу очистка остатков (каталог и пустая ветка).\n */\nexport async function finishPreparing(services: Services, id: string): Promise<void> {\n await withWorktreeLock(id, async () => {\n const worktree = services.store.getWorktree(id);\n if (worktree?.status !== 'preparing') return;\n let headSha: string;\n let foreignBranch = false;\n try {\n prepareWorktreeParent(services.dataDir, worktree.path);\n // Ветка появилась после проверки create: она чужая, git -b откажет, очистка её не тронет.\n foreignBranch = (await GitOps.branchSha(worktree.repoPath, worktree.branch)) !== undefined;\n await GitOps.addWorktree(worktree.repoPath, worktree.path, worktree.branch, worktree.baseSha);\n headSha = await GitOps.headOf(worktree.path);\n } catch (error) {\n // Остановка потребителя: preparing доведёт сверка при следующем старте.\n if (GitOps.isGitPoolClosed()) return;\n services.store.inTransaction((tx) => {\n tx.markWorktreeFailed(id, `создание не удалось: ${messageOf(error)}`, { actor: HOST_ACTOR });\n // Работы в незавершённом worktree нет: остатки убираются без проверки изменений.\n tx.requestWorktreeCleanup(id, { actor: HOST_ACTOR, discardChanges: true, foreignBranch, evidence: 'очистка после неудачного создания' });\n });\n await cleanUnderLock(services, id);\n return;\n }\n services.store.inTransaction((tx) => tx.markWorktreeReady(id, headSha, { actor: HOST_ACTOR }));\n });\n}\n\n// --- Очистка ---\n\n/** Доводит cleaning до cleaned (или failed с причиной) под замком worktree. */\nexport async function finishCleaning(services: Services, id: string): Promise<void> {\n await withWorktreeLock(id, () => cleanUnderLock(services, id));\n}\n\n/**\n * Очистка (D-079, D-088): незакоммиченные изменения без решения вызывающего — failed, каталог\n * остаётся; иначе каталог переносится в trash, git снимает worktree с учёта, ветка без\n * коммитов сверх базы удаляется, trash удаляется. Перенос не удался — failed с причиной.\n */\nasync function cleanUnderLock(services: Services, id: string): Promise<void> {\n const worktree = services.store.getWorktree(id);\n if (worktree?.status !== 'cleaning') return;\n let trashed: string | undefined;\n let flags: { discardChanges: boolean; ownsBranch: boolean };\n try {\n const present = checkManagedPath(services.dataDir, worktree.path);\n flags = services.store.worktreeCleanupFlags(id);\n if (present && !flags.discardChanges && (await GitOps.isDirty(worktree.path))) {\n services.store.inTransaction((tx) =>\n tx.markWorktreeFailed(id, 'в worktree незакоммиченные изменения: очистка ждёт решения (worktree.remove с force: true выбросит их)', {\n actor: HOST_ACTOR,\n }),\n );\n return;\n }\n if (present) {\n const trash = trashRoot(services.dataDir);\n mkdirSync(trash, { recursive: true, mode: 0o700 });\n trashed = join(trash, `${worktree.id}-${randomUUID()}`);\n renameSync(worktree.path, trashed);\n }\n } catch (error) {\n // Остановка потребителя: cleaning доведёт reconciler при следующем старте.\n if (GitOps.isGitPoolClosed()) return;\n services.store.inTransaction((tx) => tx.markWorktreeFailed(id, `очистка не удалась: ${messageOf(error)}`, { actor: HOST_ACTOR }));\n return;\n }\n // Каталог ушёл с места: дальнейшие сбои не возвращают worktree — они в журнал, а trash\n // доочищается при старте (§6.9: прерванные удаления завершаются при старте).\n await releaseGitState(services, worktree, flags.ownsBranch);\n if (GitOps.isGitPoolClosed()) return;\n if (trashed !== undefined) {\n await rm(trashed, { recursive: true, force: true }).catch((error: unknown) => {\n services.log(`worktree ${worktree.id}: trash ${trashed ?? ''} не удалён: ${messageOf(error)}`);\n });\n }\n services.store.inTransaction((tx) => tx.completeWorktreeCleanup(id, { actor: HOST_ACTOR }));\n}\n\n/** Снимает worktree с учёта репозитория и удаляет ветку host, если на ней нет работы (tip = база). */\nasync function releaseGitState(services: Services, worktree: Worktree, ownsBranch: boolean): Promise<void> {\n try {\n await GitOps.pruneWorktrees(worktree.repoPath);\n if (!ownsBranch) return;\n const tip = await GitOps.branchSha(worktree.repoPath, worktree.branch);\n if (tip !== undefined && tip === worktree.baseSha) await GitOps.deleteBranch(worktree.repoPath, worktree.branch);\n } catch (error) {\n services.log(`worktree ${worktree.id}: репозиторий ${worktree.repoPath} не обновлён после очистки: ${messageOf(error)}`);\n }\n}\n\n// --- Reconciler ---\n\n/**\n * Сверка при старте, синхронно до приёма запросов: preparing без процесса, который его вёл,\n * — failed (потребитель упал посреди создания) и сразу в очистку. Дальше работает sweep.\n */\nexport function reconcileWorktreesAtStart(services: Services): void {\n for (const worktree of services.store.worktreesInStatus(['preparing'])) {\n services.store.inTransaction((tx) => {\n tx.markWorktreeFailed(worktree.id, 'потребитель перезапущен во время создания worktree', { actor: HOST_ACTOR });\n tx.requestWorktreeCleanup(worktree.id, { actor: HOST_ACTOR, discardChanges: true, evidence: 'очистка после прерванного создания' });\n });\n }\n}\n\n/**\n * Один проход reconciler: ready worktree завершённых Task — в cleaning, все cleaning без\n * работы в этом процессе — до cleaned или failed. failed остаётся до решения (worktree.remove).\n */\nexport async function sweepWorktrees(services: Services): Promise<void> {\n for (const worktree of services.store.readyWorktreesOfSettledTasks()) {\n if (isWorktreeBusy(worktree.id)) continue;\n try {\n services.store.inTransaction((tx) => tx.requestWorktreeCleanup(worktree.id, { actor: HOST_ACTOR, evidence: 'Task завершена' }));\n } catch (error) {\n services.log(`worktree ${worktree.id}: очистка после завершения Task не началась: ${messageOf(error)}`);\n }\n }\n for (const worktree of services.store.worktreesInStatus(['cleaning'])) {\n if (isWorktreeBusy(worktree.id)) continue;\n await finishCleaning(services, worktree.id);\n }\n}\n\n/** Доочищает trash, брошенный прерванными удалениями. */\nexport async function emptyTrash(services: Services): Promise<void> {\n const trash = trashRoot(services.dataDir);\n let entries: string[];\n try {\n entries = readdirSync(trash);\n } catch {\n return;\n }\n for (const entry of entries) {\n await rm(join(trash, entry), { recursive: true, force: true }).catch((error: unknown) => {\n services.log(`trash ${entry} не удалён: ${messageOf(error)}`);\n });\n }\n}\n\n/** Запускает reconciler: сверка при старте, затем проход сразу и по таймеру. */\nexport function startWorktreeReconciler(services: Services, intervalMs = WORKTREE_RECONCILE_INTERVAL_MS): WorktreeReconciler {\n reconcileWorktreesAtStart(services);\n let current: Promise<void> = Promise.resolve();\n let stopped = false;\n const kick = (): Promise<void> => {\n if (stopped) return current;\n current = current.then(() => sweepWorktrees(services)).catch((error: unknown) => {\n services.log(`reconciler worktree: проход не удался: ${messageOf(error)}`);\n });\n return current;\n };\n current = emptyTrash(services);\n void kick();\n const timer = setInterval(() => void kick(), intervalMs);\n timer.unref();\n return {\n kick,\n stop: async () => {\n stopped = true;\n clearInterval(timer);\n await current;\n },\n };\n}\n\nexport function messageOf(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smwb/onreel-git-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"description": "Библиотека модулей, выделенных из onreel: git-операции и безопасные пути, список файлов worktree, жизненный цикл worktree против порта WorktreeStore, адаптеры трекеров GitHub/GitLab/Jira/SourceCraft/локального и MCP-сервер на stdio",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"git",
|