@smwb/onreel-git-mcp 0.12.0 → 0.13.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/README.md +15 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/tracker/index.js +30 -14
- package/dist/tracker/index.js.map +1 -1
- package/dist/tracker/secrets.lib.d.ts +14 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -894,6 +894,21 @@ console.log(manifest.name, manifest.version);
|
|
|
894
894
|
и пустая строка убирают значение. Наружу из хранилища выходит только признак «токен есть» (`hasTrackerToken`),
|
|
895
895
|
а при чтении и записи значение регистрируется в приёмнике секретов — redactor ядра и, если он задан,
|
|
896
896
|
приёмнике потребителя (см. «Маскирование секретов» ниже).
|
|
897
|
+
- **Несколько хранилищ токенов.** У проекта бывает два подключения с разными токенами — трекер задач и
|
|
898
|
+
git-хостинг, поэтому имя хранилища задаёт необязательный слот: `writeTrackerToken(dataDir, projectId, token,
|
|
899
|
+
sink, 'forge')` пишет в `<dataDir>/forge-secrets.json`, а без слота остаётся прежний `tracker-secrets.json`.
|
|
900
|
+
Те же права **0600**/0700, та же запись через временный файл и `rename`, та же очередь и та же регистрация
|
|
901
|
+
значения в приёмнике секретов; хранилища независимы — запись в одно не трогает другое, в том числе при одном
|
|
902
|
+
`projectId`. Имя файла по слоту отдаёт `trackerSecretsFile('forge')`, а `trackerSecretsFile()` —
|
|
903
|
+
`TRACKER_SECRETS_FILE`. Слот — один сегмент имени файла: строчная латиница, цифры, `-` и `_`, первый символ —
|
|
904
|
+
буква или цифра, длина не больше 64. Только строчные буквы: macOS и Windows регистр не различают, поэтому
|
|
905
|
+
`Forge` и `forge` легли бы в один файл и независимость хранилищ зависела от файловой системы. Значение
|
|
906
|
+
`tracker` зарезервировано: оно дало бы имя файла по умолчанию, то есть то же хранилище под вторым именем, и
|
|
907
|
+
запись «слота» затёрла бы токен подключения без слота. Значение вне правила (путь, `..`, пустая строка,
|
|
908
|
+
заглавные буквы, зарезервированное `tracker`) — `TrackerError('invalid_request')` до обращения к файлу, чтобы
|
|
909
|
+
слот не увёл запись из каталога данных и не затер чужой файл потребителя (ledger, настройки). Приёмник
|
|
910
|
+
секретов у `hasTrackerToken` не спрашивают — наружу эта функция отдаёт только признак «токен есть», поэтому
|
|
911
|
+
слот у неё третий параметр, а у трёх остальных — четвёртый, после `sink`.
|
|
897
912
|
- **Токен — только своему origin.** `origin(connection)` в `TrackerDefinition` — origin API, куда адаптер (и его
|
|
898
913
|
разделы `pulls`, `ci` и `repo`) ходит с токеном: `https://api.github.com`, `https://gitlab.com`,
|
|
899
914
|
`https://api.sourcecraft.tech` по умолчанию, иначе origin `url` подключения; у Jira `url` обязателен. Потребитель
|
package/dist/index.js
CHANGED
|
@@ -60,7 +60,7 @@ import {
|
|
|
60
60
|
// package.json
|
|
61
61
|
var package_default = {
|
|
62
62
|
name: "@smwb/onreel-git-mcp",
|
|
63
|
-
version: "0.
|
|
63
|
+
version: "0.13.0",
|
|
64
64
|
description: "\u0411\u0438\u0431\u043B\u0438\u043E\u0442\u0435\u043A\u0430 \u043C\u043E\u0434\u0443\u043B\u0435\u0439, \u0432\u044B\u0434\u0435\u043B\u0435\u043D\u043D\u044B\u0445 \u0438\u0437 onreel: git-\u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \u0438 \u0431\u0435\u0437\u043E\u043F\u0430\u0441\u043D\u044B\u0435 \u043F\u0443\u0442\u0438, \u0441\u043F\u0438\u0441\u043E\u043A \u0444\u0430\u0439\u043B\u043E\u0432 worktree, \u0436\u0438\u0437\u043D\u0435\u043D\u043D\u044B\u0439 \u0446\u0438\u043A\u043B worktree \u043F\u0440\u043E\u0442\u0438\u0432 \u043F\u043E\u0440\u0442\u0430 WorktreeStore, \u0430\u0434\u0430\u043F\u0442\u0435\u0440\u044B \u0442\u0440\u0435\u043A\u0435\u0440\u043E\u0432 GitHub/GitLab/Jira/SourceCraft/\u043B\u043E\u043A\u0430\u043B\u044C\u043D\u043E\u0433\u043E \u0438 MCP-\u0441\u0435\u0440\u0432\u0435\u0440 \u043D\u0430 stdio",
|
|
65
65
|
keywords: [
|
|
66
66
|
"git",
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../package.json","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@smwb/onreel-git-mcp\",\n \"version\": \"0.
|
|
1
|
+
{"version":3,"sources":["../package.json","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@smwb/onreel-git-mcp\",\n \"version\": \"0.13.0\",\n \"description\": \"Библиотека модулей, выделенных из onreel: git-операции и безопасные пути, список файлов worktree, жизненный цикл worktree против порта WorktreeStore, адаптеры трекеров GitHub/GitLab/Jira/SourceCraft/локального и MCP-сервер на stdio\",\n \"keywords\": [\n \"git\",\n \"worktree\",\n \"mcp\",\n \"issue-tracker\",\n \"github\",\n \"gitlab\",\n \"jira\",\n \"sourcecraft\",\n \"onreel\",\n \"typescript\"\n ],\n \"type\": \"module\",\n \"engines\": {\n \"node\": \">=24\"\n },\n \"files\": [\n \"dist\"\n ],\n \"sideEffects\": false,\n \"publishConfig\": {\n \"access\": \"public\",\n \"registry\": \"https://registry.npmjs.org/\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://git.sourcecraft.dev/elfenmail/onreel-git-mcp.git\"\n },\n \"homepage\": \"https://git.sourcecraft.dev/elfenmail/onreel-git-mcp\",\n \"license\": \"MIT\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"default\": \"./dist/index.js\"\n },\n \"./git\": {\n \"types\": \"./dist/git/index.d.ts\",\n \"import\": \"./dist/git/index.js\",\n \"default\": \"./dist/git/index.js\"\n },\n \"./files\": {\n \"types\": \"./dist/files/index.d.ts\",\n \"import\": \"./dist/files/index.js\",\n \"default\": \"./dist/files/index.js\"\n },\n \"./worktree\": {\n \"types\": \"./dist/worktree/index.d.ts\",\n \"import\": \"./dist/worktree/index.js\",\n \"default\": \"./dist/worktree/index.js\"\n },\n \"./tracker\": {\n \"types\": \"./dist/tracker/index.d.ts\",\n \"import\": \"./dist/tracker/index.js\",\n \"default\": \"./dist/tracker/index.js\"\n },\n \"./mcp\": {\n \"types\": \"./dist/mcp/index.d.ts\",\n \"import\": \"./dist/mcp/index.js\",\n \"default\": \"./dist/mcp/index.js\"\n },\n \"./package.json\": \"./package.json\"\n },\n \"scripts\": {\n \"build\": \"tsup && tsc -p tsconfig.build.json\",\n \"typecheck\": \"tsc -p tsconfig.json && tsc -p tsconfig.examples.json\",\n \"lint\": \"oxlint --type-aware\",\n \"test\": \"node --test \\\"test/**/*.test.ts\\\"\",\n \"changeset\": \"changeset\",\n \"version\": \"changeset version\",\n \"release\": \"npm run build && changeset publish\"\n },\n \"dependencies\": {\n \"yaml\": \"^2.9.1\",\n \"zod\": \"^4.6.5\"\n },\n \"devDependencies\": {\n \"@changesets/cli\": \"2.29.2\",\n \"@types/node\": \"24.19.1\",\n \"oxlint\": \"1.87.0\",\n \"oxlint-tsgolint\": \"7.0.2003\",\n \"tsup\": \"8.5.1\",\n \"typescript\": \"7.0.2\"\n }\n}\n","// Корневой подпуть пакета @smwb/onreel-git-mcp: срез контракта (константы, схемы, типы, чистые\n// функции) и версия пакета. Всё без побочных эффектов при импорте (R-001). Швы ядра\n// (SecretSink, WorktreeStore, LocalIssueStore) и модули git/files/worktree/tracker/mcp\n// экспортируют свои подпути — см. exports в package.json и README.\nimport pkg from '../package.json' with { type: 'json' };\n\nexport * from './contract/contract.const.ts';\nexport * from './contract/contract.schema.ts';\nexport * from './contract/contract.types.ts';\nexport * from './contract/contract.lib.ts';\n\n// Версия пакета — из version в package.json: статический импорт JSON, его значение tsup подставляет\n// в бандл на сборке, поэтому VERSION не расходится с релизом changesets (тот правит только version).\nexport const VERSION: string = pkg.version;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA,EACE,MAAQ;AAAA,EACR,SAAW;AAAA,EACX,aAAe;AAAA,EACf,UAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,MAAQ;AAAA,EACR,SAAW;AAAA,IACT,MAAQ;AAAA,EACV;AAAA,EACA,OAAS;AAAA,IACP;AAAA,EACF;AAAA,EACA,aAAe;AAAA,EACf,eAAiB;AAAA,IACf,QAAU;AAAA,IACV,UAAY;AAAA,EACd;AAAA,EACA,YAAc;AAAA,IACZ,MAAQ;AAAA,IACR,KAAO;AAAA,EACT;AAAA,EACA,UAAY;AAAA,EACZ,SAAW;AAAA,EACX,SAAW;AAAA,IACT,KAAK;AAAA,MACH,OAAS;AAAA,MACT,QAAU;AAAA,MACV,SAAW;AAAA,IACb;AAAA,IACA,SAAS;AAAA,MACP,OAAS;AAAA,MACT,QAAU;AAAA,MACV,SAAW;AAAA,IACb;AAAA,IACA,WAAW;AAAA,MACT,OAAS;AAAA,MACT,QAAU;AAAA,MACV,SAAW;AAAA,IACb;AAAA,IACA,cAAc;AAAA,MACZ,OAAS;AAAA,MACT,QAAU;AAAA,MACV,SAAW;AAAA,IACb;AAAA,IACA,aAAa;AAAA,MACX,OAAS;AAAA,MACT,QAAU;AAAA,MACV,SAAW;AAAA,IACb;AAAA,IACA,SAAS;AAAA,MACP,OAAS;AAAA,MACT,QAAU;AAAA,MACV,SAAW;AAAA,IACb;AAAA,IACA,kBAAkB;AAAA,EACpB;AAAA,EACA,SAAW;AAAA,IACT,OAAS;AAAA,IACT,WAAa;AAAA,IACb,MAAQ;AAAA,IACR,MAAQ;AAAA,IACR,WAAa;AAAA,IACb,SAAW;AAAA,IACX,SAAW;AAAA,EACb;AAAA,EACA,cAAgB;AAAA,IACd,MAAQ;AAAA,IACR,KAAO;AAAA,EACT;AAAA,EACA,iBAAmB;AAAA,IACjB,mBAAmB;AAAA,IACnB,eAAe;AAAA,IACf,QAAU;AAAA,IACV,mBAAmB;AAAA,IACnB,MAAQ;AAAA,IACR,YAAc;AAAA,EAChB;AACF;;;AC3EO,IAAM,UAAkB,gBAAI;","names":[]}
|
package/dist/tracker/index.js
CHANGED
|
@@ -3248,16 +3248,29 @@ function registerBuiltinTrackers() {
|
|
|
3248
3248
|
// src/tracker/secrets.lib.ts
|
|
3249
3249
|
import { mkdir, readFile, rename, writeFile } from "fs/promises";
|
|
3250
3250
|
import { join } from "path";
|
|
3251
|
+
var SECRETS_SLOT_PATTERN = /^[a-z0-9][a-z0-9_-]{0,63}$/;
|
|
3252
|
+
var SECRETS_FILE_SUFFIX = "-secrets.json";
|
|
3253
|
+
function trackerSecretsFile(slot) {
|
|
3254
|
+
if (slot === void 0) return TRACKER_SECRETS_FILE;
|
|
3255
|
+
if (typeof slot !== "string" || !SECRETS_SLOT_PATTERN.test(slot)) {
|
|
3256
|
+
throw new TrackerError("invalid_request", `\u0441\u043B\u043E\u0442 \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0430 \u0442\u043E\u043A\u0435\u043D\u043E\u0432 '${String(slot)}' \u0432\u043D\u0435 \u043F\u0440\u0430\u0432\u0438\u043B\u0430: \u0441\u0442\u0440\u043E\u0447\u043D\u0430\u044F \u043B\u0430\u0442\u0438\u043D\u0438\u0446\u0430, \u0446\u0438\u0444\u0440\u044B, '-' \u0438 '_', \u043F\u0435\u0440\u0432\u044B\u0439 \u0441\u0438\u043C\u0432\u043E\u043B \u2014 \u0431\u0443\u043A\u0432\u0430 \u0438\u043B\u0438 \u0446\u0438\u0444\u0440\u0430, \u0434\u043B\u0438\u043D\u0430 \u043D\u0435 \u0431\u043E\u043B\u044C\u0448\u0435 64`);
|
|
3257
|
+
}
|
|
3258
|
+
const file = `${slot}${SECRETS_FILE_SUFFIX}`;
|
|
3259
|
+
if (file === TRACKER_SECRETS_FILE) {
|
|
3260
|
+
throw new TrackerError("invalid_request", `\u0441\u043B\u043E\u0442 \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0430 \u0442\u043E\u043A\u0435\u043D\u043E\u0432 '${slot}' \u0437\u0430\u0440\u0435\u0437\u0435\u0440\u0432\u0438\u0440\u043E\u0432\u0430\u043D: \u043E\u043D \u0443\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442 \u043D\u0430 \u0444\u0430\u0439\u043B \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E ${TRACKER_SECRETS_FILE}`);
|
|
3261
|
+
}
|
|
3262
|
+
return file;
|
|
3263
|
+
}
|
|
3251
3264
|
var queue = Promise.resolve();
|
|
3252
3265
|
function exclusive(task) {
|
|
3253
3266
|
const run = queue.then(task, task);
|
|
3254
3267
|
queue = run.catch(() => void 0);
|
|
3255
3268
|
return run;
|
|
3256
3269
|
}
|
|
3257
|
-
async function readAll(dataDir) {
|
|
3270
|
+
async function readAll(dataDir, file) {
|
|
3258
3271
|
let raw;
|
|
3259
3272
|
try {
|
|
3260
|
-
raw = await readFile(join(dataDir,
|
|
3273
|
+
raw = await readFile(join(dataDir, file), "utf8");
|
|
3261
3274
|
} catch (error) {
|
|
3262
3275
|
if (error.code === "ENOENT") return {};
|
|
3263
3276
|
throw error;
|
|
@@ -3266,32 +3279,34 @@ async function readAll(dataDir) {
|
|
|
3266
3279
|
if (!isRecord(parsed)) return {};
|
|
3267
3280
|
return Object.fromEntries(Object.entries(parsed).filter((entry) => typeof entry[1] === "string"));
|
|
3268
3281
|
}
|
|
3269
|
-
async function writeAll(dataDir, secrets) {
|
|
3282
|
+
async function writeAll(dataDir, file, secrets) {
|
|
3270
3283
|
await mkdir(dataDir, { recursive: true, mode: 448 });
|
|
3271
|
-
const target = join(dataDir,
|
|
3284
|
+
const target = join(dataDir, file);
|
|
3272
3285
|
const temp = `${target}.${String(process.pid)}.tmp`;
|
|
3273
3286
|
await writeFile(temp, JSON.stringify(secrets), { mode: 384 });
|
|
3274
3287
|
await rename(temp, target);
|
|
3275
3288
|
}
|
|
3276
|
-
async function readTrackerToken(dataDir, projectId, sink = defaultSecretSink) {
|
|
3277
|
-
const token = (await readAll(dataDir))[projectId];
|
|
3289
|
+
async function readTrackerToken(dataDir, projectId, sink = defaultSecretSink, slot) {
|
|
3290
|
+
const token = (await readAll(dataDir, trackerSecretsFile(slot)))[projectId];
|
|
3278
3291
|
if (token !== void 0) sink.register(token);
|
|
3279
3292
|
return token;
|
|
3280
3293
|
}
|
|
3281
|
-
function hasTrackerToken(dataDir, projectId) {
|
|
3282
|
-
|
|
3294
|
+
async function hasTrackerToken(dataDir, projectId, slot) {
|
|
3295
|
+
const secrets = await readAll(dataDir, trackerSecretsFile(slot));
|
|
3296
|
+
return secrets[projectId] !== void 0;
|
|
3283
3297
|
}
|
|
3284
|
-
function writeTrackerToken(dataDir, projectId, token, sink = defaultSecretSink) {
|
|
3298
|
+
async function writeTrackerToken(dataDir, projectId, token, sink = defaultSecretSink, slot) {
|
|
3299
|
+
const file = trackerSecretsFile(slot);
|
|
3285
3300
|
if (token !== "") sink.register(token);
|
|
3286
|
-
|
|
3287
|
-
const secrets = await readAll(dataDir);
|
|
3301
|
+
await exclusive(async () => {
|
|
3302
|
+
const secrets = await readAll(dataDir, file);
|
|
3288
3303
|
if (token === "") delete secrets[projectId];
|
|
3289
3304
|
else secrets[projectId] = token;
|
|
3290
|
-
await writeAll(dataDir, secrets);
|
|
3305
|
+
await writeAll(dataDir, file, secrets);
|
|
3291
3306
|
});
|
|
3292
3307
|
}
|
|
3293
|
-
function deleteTrackerToken(dataDir, projectId, sink = defaultSecretSink) {
|
|
3294
|
-
return writeTrackerToken(dataDir, projectId, "", sink);
|
|
3308
|
+
function deleteTrackerToken(dataDir, projectId, sink = defaultSecretSink, slot) {
|
|
3309
|
+
return writeTrackerToken(dataDir, projectId, "", sink, slot);
|
|
3295
3310
|
}
|
|
3296
3311
|
|
|
3297
3312
|
// src/tracker/pull.lib.ts
|
|
@@ -5315,6 +5330,7 @@ export {
|
|
|
5315
5330
|
text,
|
|
5316
5331
|
toTimestamp,
|
|
5317
5332
|
trackerConfigSchema,
|
|
5333
|
+
trackerSecretsFile,
|
|
5318
5334
|
usedFilters,
|
|
5319
5335
|
validateTrackerConfig,
|
|
5320
5336
|
writeTrackerToken
|