438 lines
21 KiB
JavaScript
438 lines
21 KiB
JavaScript
"use strict";
|
|
var __assign = (this && this.__assign) || function () {
|
|
__assign = Object.assign || function(t) {
|
|
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
s = arguments[i];
|
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
t[p] = s[p];
|
|
}
|
|
return t;
|
|
};
|
|
return __assign.apply(this, arguments);
|
|
};
|
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
});
|
|
};
|
|
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
function step(op) {
|
|
if (f) throw new TypeError("Generator is already executing.");
|
|
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
switch (op[0]) {
|
|
case 0: case 1: t = op; break;
|
|
case 4: _.label++; return { value: op[1], done: false };
|
|
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
default:
|
|
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
if (t[2]) _.ops.pop();
|
|
_.trys.pop(); continue;
|
|
}
|
|
op = body.call(thisArg, _);
|
|
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
}
|
|
};
|
|
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
if (ar || !(i in from)) {
|
|
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
ar[i] = from[i];
|
|
}
|
|
}
|
|
return to.concat(ar || Array.prototype.slice.call(from));
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.DEFAULT_AUTOMATION_CONTEXTS = void 0;
|
|
exports.sanitizeAutomationContexts = sanitizeAutomationContexts;
|
|
exports.getAutomationContextsConfig = getAutomationContextsConfig;
|
|
exports.upsertAutomationContextsConfig = upsertAutomationContextsConfig;
|
|
exports.normalizeAutomationContextSelection = normalizeAutomationContextSelection;
|
|
exports.resolveAutomationContexts = resolveAutomationContexts;
|
|
var client_js_1 = require("../db/client.js");
|
|
var AUTOMATION_CONTEXTS_TABLE = 'automation_contexts';
|
|
exports.DEFAULT_AUTOMATION_CONTEXTS = [
|
|
{
|
|
id: 'general-inquiry-default',
|
|
title: '기본 확인',
|
|
content: '소스 수정 없이 조회, 상태 확인, 응답 정리를 우선합니다.',
|
|
enabled: true,
|
|
defaultSelected: true,
|
|
updatedAt: '2026-04-29T00:00:00.000Z',
|
|
},
|
|
{
|
|
id: 'none-default',
|
|
title: '기본 처리',
|
|
content: '## 기본 처리\n- 현재 저장소 규칙과 요청 본문을 우선 따릅니다.\n- 소스 수정이 필요하면 관련 파일을 수정하고, 필요 없으면 확인 결과만 정리합니다.\n- 작업 결과에는 변경 파일, diff, preview 같은 증적을 남길 수 있습니다.',
|
|
enabled: true,
|
|
defaultSelected: true,
|
|
updatedAt: '2026-04-29T00:00:00.000Z',
|
|
},
|
|
{
|
|
id: 'plan-default',
|
|
title: '문서형 처리',
|
|
content: 'Plan 등록/문서형 요청으로 처리하고, 구현보다 등록/정리 결과를 우선 남깁니다.',
|
|
enabled: true,
|
|
defaultSelected: false,
|
|
updatedAt: '2026-04-29T00:00:00.000Z',
|
|
},
|
|
{
|
|
id: 'command-execution-default',
|
|
title: '명령 실행',
|
|
content: '저장소 수정 없이 명령 실행, API 확인, 상태 조회 중심으로 처리합니다.',
|
|
enabled: true,
|
|
defaultSelected: false,
|
|
updatedAt: '2026-04-29T00:00:00.000Z',
|
|
},
|
|
{
|
|
id: 'non-source-work-default',
|
|
title: '비소스 작업',
|
|
content: '문서, 운영, 데이터 확인 등 비소스 작업으로 처리하고 코드 수정은 요청 시에만 제한적으로 수행합니다.',
|
|
enabled: true,
|
|
defaultSelected: false,
|
|
updatedAt: '2026-04-29T00:00:00.000Z',
|
|
},
|
|
{
|
|
id: 'auto-worker-default',
|
|
title: '자동화 기본 규칙',
|
|
content: '## context 사용 규칙\n- 자동화 실행기는 선택된 Context만 우선 참조합니다.\n- Codex Live 문맥이나 일반 채팅 문맥은 자동화 기본 context로 섞지 않습니다.\n\n## 처리 원칙\n- 세부 절차는 현재 운영 설정을 따릅니다.',
|
|
enabled: true,
|
|
defaultSelected: true,
|
|
updatedAt: '2026-04-29T00:00:00.000Z',
|
|
},
|
|
];
|
|
function normalizeText(value) {
|
|
return typeof value === 'string' ? value.trim() : '';
|
|
}
|
|
function normalizeEnabled(value) {
|
|
if (typeof value === 'boolean') {
|
|
return value;
|
|
}
|
|
if (typeof value === 'number') {
|
|
return value !== 0;
|
|
}
|
|
if (typeof value === 'string') {
|
|
var normalizedValue = value.trim().toLowerCase();
|
|
if (['false', '0', 'n', 'no', 'off'].includes(normalizedValue)) {
|
|
return false;
|
|
}
|
|
if (['true', '1', 'y', 'yes', 'on'].includes(normalizedValue)) {
|
|
return true;
|
|
}
|
|
}
|
|
return value !== false;
|
|
}
|
|
function buildContextTitleKey(value) {
|
|
return value.replace(/\s+/g, ' ').toLocaleLowerCase('ko-KR');
|
|
}
|
|
function compareContextUpdatedAt(left, right) {
|
|
var leftTime = Date.parse(left.updatedAt);
|
|
var rightTime = Date.parse(right.updatedAt);
|
|
if (Number.isFinite(leftTime) && Number.isFinite(rightTime) && leftTime !== rightTime) {
|
|
return leftTime - rightTime;
|
|
}
|
|
return 0;
|
|
}
|
|
function normalizeAutomationContext(record) {
|
|
var title = normalizeText(record.title);
|
|
var content = normalizeText(record.content);
|
|
if (!title && !content) {
|
|
return null;
|
|
}
|
|
var rawId = normalizeText(record.id);
|
|
var normalizedId = rawId || "automation-context-".concat(Date.now().toString(36), "-").concat(Math.random().toString(36).slice(2, 8));
|
|
return {
|
|
id: normalizedId,
|
|
title: title || 'Context',
|
|
content: content,
|
|
enabled: normalizeEnabled(record.enabled),
|
|
defaultSelected: normalizeEnabled(record.defaultSelected),
|
|
updatedAt: normalizeText(record.updatedAt) || new Date().toISOString(),
|
|
};
|
|
}
|
|
function sanitizeAutomationContexts(items) {
|
|
var byId = new Map();
|
|
var bySemanticKey = new Map();
|
|
(items !== null && items !== void 0 ? items : [])
|
|
.map(function (item) { return normalizeAutomationContext(item); })
|
|
.filter(function (item) { return Boolean(item); })
|
|
.forEach(function (item) {
|
|
var currentById = byId.get(item.id);
|
|
if (!currentById || compareContextUpdatedAt(currentById, item) <= 0) {
|
|
byId.set(item.id, item);
|
|
}
|
|
});
|
|
for (var _i = 0, _a = byId.values(); _i < _a.length; _i++) {
|
|
var item = _a[_i];
|
|
var semanticKey = buildContextTitleKey(item.title);
|
|
var current = bySemanticKey.get(semanticKey);
|
|
if (!current || compareContextUpdatedAt(current, item) <= 0) {
|
|
bySemanticKey.set(semanticKey, item);
|
|
}
|
|
}
|
|
var values = Array.from(bySemanticKey.values()).sort(function (left, right) { return left.title.localeCompare(right.title, 'ko-KR'); });
|
|
return values.length > 0 ? values : exports.DEFAULT_AUTOMATION_CONTEXTS;
|
|
}
|
|
function ensureAutomationContextsTable() {
|
|
return __awaiter(this, void 0, void 0, function () {
|
|
var hasTable, requiredColumns, _loop_1, _i, requiredColumns_1, _a, columnName, createColumn;
|
|
return __generator(this, function (_b) {
|
|
switch (_b.label) {
|
|
case 0: return [4 /*yield*/, client_js_1.db.schema.hasTable(AUTOMATION_CONTEXTS_TABLE)];
|
|
case 1:
|
|
hasTable = _b.sent();
|
|
if (!!hasTable) return [3 /*break*/, 3];
|
|
return [4 /*yield*/, client_js_1.db.schema.createTable(AUTOMATION_CONTEXTS_TABLE, function (table) {
|
|
table.string('id').primary();
|
|
table.string('title').notNullable();
|
|
table.text('content').notNullable().defaultTo('');
|
|
table.boolean('enabled').notNullable().defaultTo(true);
|
|
table.boolean('default_selected').notNullable().defaultTo(false);
|
|
table.timestamp('updated_at', { useTz: true }).notNullable().defaultTo(client_js_1.db.fn.now());
|
|
})];
|
|
case 2:
|
|
_b.sent();
|
|
return [2 /*return*/];
|
|
case 3:
|
|
requiredColumns = [
|
|
['title', function (table) { return table.string('title').notNullable().defaultTo(''); }],
|
|
['content', function (table) { return table.text('content').notNullable().defaultTo(''); }],
|
|
['enabled', function (table) { return table.boolean('enabled').notNullable().defaultTo(true); }],
|
|
['default_selected', function (table) { return table.boolean('default_selected').notNullable().defaultTo(false); }],
|
|
['updated_at', function (table) { return table.timestamp('updated_at', { useTz: true }).notNullable().defaultTo(client_js_1.db.fn.now()); }],
|
|
];
|
|
_loop_1 = function (columnName, createColumn) {
|
|
var hasColumn;
|
|
return __generator(this, function (_c) {
|
|
switch (_c.label) {
|
|
case 0: return [4 /*yield*/, client_js_1.db.schema.hasColumn(AUTOMATION_CONTEXTS_TABLE, columnName)];
|
|
case 1:
|
|
hasColumn = _c.sent();
|
|
if (!!hasColumn) return [3 /*break*/, 3];
|
|
return [4 /*yield*/, client_js_1.db.schema.alterTable(AUTOMATION_CONTEXTS_TABLE, function (table) {
|
|
createColumn(table);
|
|
})];
|
|
case 2:
|
|
_c.sent();
|
|
_c.label = 3;
|
|
case 3: return [2 /*return*/];
|
|
}
|
|
});
|
|
};
|
|
_i = 0, requiredColumns_1 = requiredColumns;
|
|
_b.label = 4;
|
|
case 4:
|
|
if (!(_i < requiredColumns_1.length)) return [3 /*break*/, 7];
|
|
_a = requiredColumns_1[_i], columnName = _a[0], createColumn = _a[1];
|
|
return [5 /*yield**/, _loop_1(columnName, createColumn)];
|
|
case 5:
|
|
_b.sent();
|
|
_b.label = 6;
|
|
case 6:
|
|
_i++;
|
|
return [3 /*break*/, 4];
|
|
case 7: return [2 /*return*/];
|
|
}
|
|
});
|
|
});
|
|
}
|
|
function parseContextsFromLegacyValue(value) {
|
|
if (typeof value !== 'string') {
|
|
return [];
|
|
}
|
|
try {
|
|
var parsed = JSON.parse(value);
|
|
return Array.isArray(parsed) ? parsed : [];
|
|
}
|
|
catch (_a) {
|
|
return [];
|
|
}
|
|
}
|
|
function toAutomationContextRecord(row) {
|
|
return normalizeAutomationContext({
|
|
id: typeof row.id === 'string' ? row.id : undefined,
|
|
title: typeof row.title === 'string' ? row.title : undefined,
|
|
content: typeof row.content === 'string' ? row.content : undefined,
|
|
enabled: normalizeEnabled(row.enabled),
|
|
defaultSelected: normalizeEnabled(row.default_selected),
|
|
updatedAt: typeof row.updated_at === 'string' ? row.updated_at : undefined,
|
|
});
|
|
}
|
|
function replaceAutomationContextsInTable(items) {
|
|
return __awaiter(this, void 0, void 0, function () {
|
|
var nextItems;
|
|
var _this = this;
|
|
return __generator(this, function (_a) {
|
|
switch (_a.label) {
|
|
case 0: return [4 /*yield*/, ensureAutomationContextsTable()];
|
|
case 1:
|
|
_a.sent();
|
|
nextItems = sanitizeAutomationContexts(items);
|
|
return [4 /*yield*/, client_js_1.db.transaction(function (trx) { return __awaiter(_this, void 0, void 0, function () {
|
|
return __generator(this, function (_a) {
|
|
switch (_a.label) {
|
|
case 0: return [4 /*yield*/, trx(AUTOMATION_CONTEXTS_TABLE).del()];
|
|
case 1:
|
|
_a.sent();
|
|
return [4 /*yield*/, trx(AUTOMATION_CONTEXTS_TABLE).insert(nextItems.map(function (item) { return ({
|
|
id: item.id,
|
|
title: item.title,
|
|
content: item.content,
|
|
enabled: item.enabled,
|
|
default_selected: item.defaultSelected,
|
|
updated_at: item.updatedAt,
|
|
}); }))];
|
|
case 2:
|
|
_a.sent();
|
|
return [2 /*return*/];
|
|
}
|
|
});
|
|
}); })];
|
|
case 2:
|
|
_a.sent();
|
|
return [2 /*return*/, nextItems];
|
|
}
|
|
});
|
|
});
|
|
}
|
|
function seedAutomationContextsFromLegacySources() {
|
|
return __awaiter(this, void 0, void 0, function () {
|
|
var seededItems, hasAutomationTypesTable, rows, _i, rows_1, row;
|
|
return __generator(this, function (_a) {
|
|
switch (_a.label) {
|
|
case 0:
|
|
seededItems = __spreadArray([], exports.DEFAULT_AUTOMATION_CONTEXTS, true);
|
|
return [4 /*yield*/, client_js_1.db.schema.hasTable('automation_types')];
|
|
case 1:
|
|
hasAutomationTypesTable = _a.sent();
|
|
if (!hasAutomationTypesTable) return [3 /*break*/, 3];
|
|
return [4 /*yield*/, (0, client_js_1.db)('automation_types').select('contexts_json')];
|
|
case 2:
|
|
rows = _a.sent();
|
|
for (_i = 0, rows_1 = rows; _i < rows_1.length; _i++) {
|
|
row = rows_1[_i];
|
|
seededItems.push.apply(seededItems, parseContextsFromLegacyValue(row.contexts_json));
|
|
}
|
|
_a.label = 3;
|
|
case 3: return [2 /*return*/, replaceAutomationContextsInTable(sanitizeAutomationContexts(seededItems))];
|
|
}
|
|
});
|
|
});
|
|
}
|
|
function isSameAutomationContextList(left, right) {
|
|
if (left.length !== right.length) {
|
|
return false;
|
|
}
|
|
return left.every(function (item, index) {
|
|
var target = right[index];
|
|
return (target &&
|
|
item.id === target.id &&
|
|
item.title === target.title &&
|
|
item.content === target.content &&
|
|
item.enabled === target.enabled &&
|
|
item.defaultSelected === target.defaultSelected &&
|
|
item.updatedAt === target.updatedAt);
|
|
});
|
|
}
|
|
function mergeDefaultAutomationContexts(items) {
|
|
var byId = new Map(items.map(function (item) { return [item.id, item]; }));
|
|
for (var _i = 0, DEFAULT_AUTOMATION_CONTEXTS_1 = exports.DEFAULT_AUTOMATION_CONTEXTS; _i < DEFAULT_AUTOMATION_CONTEXTS_1.length; _i++) {
|
|
var defaultItem = DEFAULT_AUTOMATION_CONTEXTS_1[_i];
|
|
var existingItem = byId.get(defaultItem.id);
|
|
if (!existingItem) {
|
|
byId.set(defaultItem.id, defaultItem);
|
|
continue;
|
|
}
|
|
byId.set(defaultItem.id, __assign(__assign({}, existingItem), { title: defaultItem.title, content: existingItem.content || defaultItem.content }));
|
|
}
|
|
return sanitizeAutomationContexts(Array.from(byId.values()));
|
|
}
|
|
function readAutomationContextsFromTable() {
|
|
return __awaiter(this, void 0, void 0, function () {
|
|
var rows, savedItems;
|
|
return __generator(this, function (_a) {
|
|
switch (_a.label) {
|
|
case 0: return [4 /*yield*/, ensureAutomationContextsTable()];
|
|
case 1:
|
|
_a.sent();
|
|
return [4 /*yield*/, (0, client_js_1.db)(AUTOMATION_CONTEXTS_TABLE)
|
|
.select('id', 'title', 'content', 'enabled', 'default_selected', 'updated_at')
|
|
.orderBy('title', 'asc')];
|
|
case 2:
|
|
rows = _a.sent();
|
|
savedItems = rows
|
|
.map(function (row) { return toAutomationContextRecord(row); })
|
|
.filter(function (item) { return Boolean(item); });
|
|
return [2 /*return*/, sanitizeAutomationContexts(savedItems)];
|
|
}
|
|
});
|
|
});
|
|
}
|
|
function getAutomationContextsConfig() {
|
|
return __awaiter(this, void 0, void 0, function () {
|
|
var savedContexts, mergedContexts;
|
|
return __generator(this, function (_a) {
|
|
switch (_a.label) {
|
|
case 0: return [4 /*yield*/, readAutomationContextsFromTable()];
|
|
case 1:
|
|
savedContexts = _a.sent();
|
|
if (savedContexts.length === 0 || savedContexts === exports.DEFAULT_AUTOMATION_CONTEXTS) {
|
|
return [2 /*return*/, seedAutomationContextsFromLegacySources()];
|
|
}
|
|
mergedContexts = mergeDefaultAutomationContexts(savedContexts);
|
|
if (!!isSameAutomationContextList(savedContexts, mergedContexts)) return [3 /*break*/, 3];
|
|
return [4 /*yield*/, replaceAutomationContextsInTable(mergedContexts)];
|
|
case 2:
|
|
_a.sent();
|
|
_a.label = 3;
|
|
case 3: return [2 /*return*/, mergedContexts];
|
|
}
|
|
});
|
|
});
|
|
}
|
|
function upsertAutomationContextsConfig(items) {
|
|
return __awaiter(this, void 0, void 0, function () {
|
|
var nextContexts;
|
|
return __generator(this, function (_a) {
|
|
nextContexts = mergeDefaultAutomationContexts(sanitizeAutomationContexts(Array.isArray(items) ? items : []));
|
|
return [2 /*return*/, replaceAutomationContextsInTable(nextContexts)];
|
|
});
|
|
});
|
|
}
|
|
function normalizeAutomationContextSelection(value) {
|
|
var rawValues = Array.isArray(value)
|
|
? value
|
|
: typeof value === 'string'
|
|
? value
|
|
.split(',')
|
|
.map(function (item) { return item.trim(); })
|
|
.filter(Boolean)
|
|
: [];
|
|
return __spreadArray([], new Set(rawValues.map(function (item) { return normalizeText(String(item)); }).filter(Boolean)), true);
|
|
}
|
|
function resolveAutomationContexts(contexts, selectedContextIds) {
|
|
var normalizedContexts = sanitizeAutomationContexts(contexts);
|
|
var requestedIds = normalizeAutomationContextSelection(selectedContextIds);
|
|
if (requestedIds.length === 0 && Array.isArray(selectedContextIds)) {
|
|
return [];
|
|
}
|
|
if (requestedIds.length === 0) {
|
|
return normalizedContexts.filter(function (item) { return item.enabled && item.defaultSelected; });
|
|
}
|
|
var requestedIdSet = new Set(requestedIds);
|
|
return normalizedContexts.filter(function (item) { return requestedIdSet.has(item.id); });
|
|
}
|