ai-ops-compiler 0.1.1 → 0.1.3

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/dist/index.d.ts CHANGED
@@ -229,16 +229,18 @@ declare const TOOL_OUTPUT_MAP: {
229
229
  readonly mode: "multi-file";
230
230
  readonly rulesDir: ".claude/rules";
231
231
  readonly fileExtension: ".md";
232
- readonly contextStrategy: "path-scoped";
232
+ readonly contextStrategy: "hybrid";
233
233
  };
234
234
  readonly codex: {
235
235
  readonly mode: "multi-file";
236
+ readonly dir: ".codex";
236
237
  readonly rootFileName: "AGENTS.md";
237
238
  readonly domainFileName: "AGENTS.override.md";
238
239
  readonly contextStrategy: "hierarchical";
239
240
  };
240
241
  readonly gemini: {
241
242
  readonly mode: "multi-file";
243
+ readonly dir: ".gemini";
242
244
  readonly rootFileName: "GEMINI.md";
243
245
  readonly domainFileName: "GEMINI.md";
244
246
  readonly contextStrategy: "hierarchical";
@@ -256,11 +258,15 @@ declare const partitionRules: (rules: readonly Rule[]) => {
256
258
  domain: Rule[];
257
259
  };
258
260
  declare const renderFrontmatter: (paths: readonly string[]) => string;
261
+ type WorkspaceMapping = {
262
+ path: string;
263
+ ruleIds: readonly string[];
264
+ };
259
265
  declare const renderClaudeCodeRule: (rule: Rule) => string;
260
266
  type ClaudeCodeRenderResult = {
261
267
  tool: 'claude-code';
262
268
  files: {
263
- fileName: string;
269
+ relativePath: string;
264
270
  content: string;
265
271
  }[];
266
272
  };
@@ -275,7 +281,7 @@ type GeminiRenderResult = {
275
281
  domainContent: string;
276
282
  };
277
283
  type ToolRenderResult = ClaudeCodeRenderResult | CodexRenderResult | GeminiRenderResult;
278
- declare const renderForTool: (toolId: ToolId, rules: readonly Rule[]) => ToolRenderResult;
284
+ declare const renderForTool: (toolId: ToolId, rules: readonly Rule[], workspaceMappings?: readonly WorkspaceMapping[]) => ToolRenderResult;
279
285
 
280
286
  declare const computeHash: (contents: readonly string[]) => string;
281
287
  declare const computeSourceHash: (rulesDir: string) => string;
@@ -336,4 +342,4 @@ declare const buildInstallPlan: (params: {
336
342
 
337
343
  declare const COMPILER_DATA_DIR: string;
338
344
 
339
- export { CLAUDE_CODE_PATH_GLOBS, COMPILER_DATA_DIR, type ClaudeCodeRenderResult, type CodexRenderResult, type DecisionTableEntry, DecisionTableEntrySchema, type DiffResult, type FileAction, GLOBAL_CATEGORIES, type GeminiRenderResult, MANIFEST_FILENAME, type Manifest, ManifestSchema, type Preset, PresetSchema, type Rule, type RuleContent, RuleContentSchema, RuleSchema, SCOPES, TOOL_OUTPUT_MAP, type ToolId, type ToolRenderResult, type WorkspaceEntry, buildInstallPlan, buildManifest, computeDiff, computeHash, computeSourceHash, excludeRules, isGlobalRule, isManagedFile, loadAllRules, loadPresets, loadRuleFile, parseManagedHeader, parseManifest, parseRawPresets, partitionRules, readManifest, renderClaudeCodeRule, renderDecisionTable, renderForTool, renderFrontmatter, renderRuleToMarkdown, renderRulesToMarkdown, resolveManifestPath, resolvePresetRules, ruleIdToTitle, serializeManifest, sortRulesByPriority, stripManagedHeader, wrapWithHeader, writeManifest };
345
+ export { CLAUDE_CODE_PATH_GLOBS, COMPILER_DATA_DIR, type ClaudeCodeRenderResult, type CodexRenderResult, type DecisionTableEntry, DecisionTableEntrySchema, type DiffResult, type FileAction, GLOBAL_CATEGORIES, type GeminiRenderResult, MANIFEST_FILENAME, type Manifest, ManifestSchema, type Preset, PresetSchema, type Rule, type RuleContent, RuleContentSchema, RuleSchema, SCOPES, TOOL_OUTPUT_MAP, type ToolId, type ToolRenderResult, type WorkspaceEntry, type WorkspaceMapping, buildInstallPlan, buildManifest, computeDiff, computeHash, computeSourceHash, excludeRules, isGlobalRule, isManagedFile, loadAllRules, loadPresets, loadRuleFile, parseManagedHeader, parseManifest, parseRawPresets, partitionRules, readManifest, renderClaudeCodeRule, renderDecisionTable, renderForTool, renderFrontmatter, renderRuleToMarkdown, renderRulesToMarkdown, resolveManifestPath, resolvePresetRules, ruleIdToTitle, serializeManifest, sortRulesByPriority, stripManagedHeader, wrapWithHeader, writeManifest };
package/dist/index.js CHANGED
@@ -86,6 +86,9 @@ var loadPresets = (presetsPath) => {
86
86
  return parseRawPresets(data);
87
87
  };
88
88
 
89
+ // src/renderer.ts
90
+ import { join } from "path";
91
+
89
92
  // src/tool-output.ts
90
93
  var GLOBAL_CATEGORIES = ["persona", "communication", "philosophy", "convention", "standard"];
91
94
  var CLAUDE_CODE_PATH_GLOBS = {
@@ -113,11 +116,12 @@ var TOOL_OUTPUT_MAP = {
113
116
  mode: "multi-file",
114
117
  rulesDir: ".claude/rules",
115
118
  fileExtension: ".md",
116
- contextStrategy: "path-scoped"
117
- // paths: frontmatter
119
+ // single: path-scoped (paths: frontmatter) / monorepo: hierarchical ({workspace}/CLAUDE.md)
120
+ contextStrategy: "hybrid"
118
121
  },
119
122
  codex: {
120
123
  mode: "multi-file",
124
+ dir: ".codex",
121
125
  rootFileName: "AGENTS.md",
122
126
  // global 룰
123
127
  domainFileName: "AGENTS.override.md",
@@ -127,6 +131,7 @@ var TOOL_OUTPUT_MAP = {
127
131
  },
128
132
  gemini: {
129
133
  mode: "multi-file",
134
+ dir: ".gemini",
130
135
  rootFileName: "GEMINI.md",
131
136
  // global 룰
132
137
  domainFileName: "GEMINI.md",
@@ -199,17 +204,35 @@ ${renderRuleToMarkdown(rule)}`;
199
204
  }
200
205
  return renderRuleToMarkdown(rule);
201
206
  };
202
- var renderForTool = (toolId, rules) => {
203
- const { global, domain } = partitionRules(rules);
207
+ var renderForTool = (toolId, rules, workspaceMappings) => {
204
208
  const config = TOOL_OUTPUT_MAP[toolId];
205
209
  if (toolId === "claude-code") {
206
- const { fileExtension } = config;
207
- const files = rules.map((rule) => ({
208
- fileName: `${rule.id}${fileExtension}`,
209
- content: renderClaudeCodeRule(rule)
210
+ const { rulesDir, fileExtension } = config;
211
+ if (!workspaceMappings || workspaceMappings.length === 0) {
212
+ const files = rules.map((rule) => ({
213
+ relativePath: join(rulesDir, `${rule.id}${fileExtension}`),
214
+ content: renderClaudeCodeRule(rule)
215
+ }));
216
+ return { tool: "claude-code", files };
217
+ }
218
+ const { global: global2, domain: domain2 } = partitionRules(rules);
219
+ const globalFiles = global2.map((rule) => ({
220
+ relativePath: join(rulesDir, `${rule.id}${fileExtension}`),
221
+ content: renderRuleToMarkdown(rule)
222
+ // global은 frontmatter 불필요
210
223
  }));
211
- return { tool: "claude-code", files };
224
+ const workspaceFiles = [];
225
+ for (const ws of workspaceMappings) {
226
+ const wsRules = domain2.filter((r) => ws.ruleIds.includes(r.id));
227
+ if (wsRules.length === 0) continue;
228
+ workspaceFiles.push({
229
+ relativePath: join(ws.path, "CLAUDE.md"),
230
+ content: renderRulesToMarkdown(wsRules)
231
+ });
232
+ }
233
+ return { tool: "claude-code", files: [...globalFiles, ...workspaceFiles] };
212
234
  }
235
+ const { global, domain } = partitionRules(rules);
213
236
  const rootContent = renderRulesToMarkdown(global);
214
237
  const domainContent = renderRulesToMarkdown(domain);
215
238
  if (toolId === "codex") {
@@ -266,11 +289,11 @@ var stripManagedHeader = (content) => {
266
289
 
267
290
  // src/manifest-io.ts
268
291
  import { mkdirSync, readFileSync as readFileSync3, writeFileSync } from "fs";
269
- import { dirname, join } from "path";
292
+ import { dirname, join as join2 } from "path";
270
293
  var MANIFEST_FILENAME = ".ai-ops-manifest.json";
271
294
  var parseManifest = (json) => ManifestSchema.parse(JSON.parse(json));
272
295
  var serializeManifest = (manifest) => JSON.stringify(manifest, null, 2) + "\n";
273
- var resolveManifestPath = (basePath) => join(basePath, MANIFEST_FILENAME);
296
+ var resolveManifestPath = (basePath) => join2(basePath, MANIFEST_FILENAME);
274
297
  var readManifest = (manifestPath) => {
275
298
  let raw;
276
299
  try {
@@ -298,13 +321,12 @@ var computeDiff = (params) => {
298
321
  };
299
322
 
300
323
  // src/install-plan.ts
301
- import { join as join2 } from "path";
324
+ import { join as join3 } from "path";
302
325
  var buildInstallPlan = (params) => {
303
326
  const { toolId, renderResult, meta } = params;
304
327
  if (toolId === "claude-code" && renderResult.tool === "claude-code") {
305
- const { rulesDir } = TOOL_OUTPUT_MAP["claude-code"];
306
- return renderResult.files.map(({ fileName, content }) => ({
307
- relativePath: join2(rulesDir, fileName),
328
+ return renderResult.files.map(({ relativePath, content }) => ({
329
+ relativePath,
308
330
  content: wrapWithHeader(content, meta)
309
331
  }));
310
332
  }
@@ -313,13 +335,13 @@ var buildInstallPlan = (params) => {
313
335
  const actions = [];
314
336
  if (renderResult.rootContent) {
315
337
  actions.push({
316
- relativePath: config.rootFileName,
338
+ relativePath: join3(config.dir, config.rootFileName),
317
339
  content: wrapWithHeader(renderResult.rootContent, meta)
318
340
  });
319
341
  }
320
342
  if (renderResult.domainContent) {
321
343
  actions.push({
322
- relativePath: config.domainFileName,
344
+ relativePath: join3(config.dir, config.domainFileName),
323
345
  content: wrapWithHeader(renderResult.domainContent, meta)
324
346
  });
325
347
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/schemas/rule.schema.ts","../src/schemas/preset.schema.ts","../src/schemas/manifest.schema.ts","../src/loader.ts","../src/tool-output.ts","../src/renderer.ts","../src/source-hash.ts","../src/managed-header.ts","../src/manifest-io.ts","../src/diff.ts","../src/install-plan.ts","../src/paths.ts"],"sourcesContent":["/**\n * Rule = SSOT의 최소 지식 단위. 하나의 코딩 컨벤션/아키텍처 규칙을 YAML로 구조화한 것.\n */\nimport { z } from 'zod';\n\nexport const DecisionTableEntrySchema = z\n .object({\n when: z.string().min(1),\n then: z.string().min(1),\n /** 조건부 규칙에서 회피해야 할 패턴 */\n avoid: z.string().min(1).optional(),\n })\n .strict();\n\nexport const RuleContentSchema = z\n .object({\n /** Anti-pattern 규칙 ('하지 마라'). guidelines보다 항상 상단 렌더링 */\n constraints: z.array(z.string().min(1)),\n /** Positive 규칙 ('해라') */\n guidelines: z.array(z.string().min(1)),\n /** 조건부 규칙. when→then→avoid 구조 */\n decision_table: z.array(DecisionTableEntrySchema).optional(),\n })\n .strict();\n\nexport const RuleSchema = z\n .object({\n id: z.string().regex(/^[a-z0-9]+(-[a-z0-9]+)*$/, 'id must be kebab-case'),\n category: z.string().min(1),\n tags: z.array(z.string().min(1)),\n /** 0-100. 높을수록 생성 파일 상단 배치 (U-shaped attention 최적화) */\n priority: z.number().int().min(0).max(100),\n content: RuleContentSchema,\n })\n .strict();\n\nexport type DecisionTableEntry = z.infer<typeof DecisionTableEntrySchema>;\nexport type RuleContent = z.infer<typeof RuleContentSchema>;\nexport type Rule = z.infer<typeof RuleSchema>;\n","import { z } from 'zod';\n\nexport const PresetSchema = z\n .object({\n id: z\n .string()\n .regex(/^[a-z][a-z0-9-]*$/)\n .min(1),\n description: z.string().min(1),\n rules: z.array(z.string().min(1)).min(1),\n })\n .strict();\n\nexport type Preset = z.infer<typeof PresetSchema>;\n","/**\n * Manifest = 설치 추적 메타데이터. CLI가 이전 설치 상태를 기억하기 위한 JSON.\n */\nimport { z } from 'zod';\n\nexport const SCOPES = {\n PROJECT: 'project',\n GLOBAL: 'global',\n} as const;\n\n/** 모노레포 워크스페이스별 preset + rules 추적 */\nconst WorkspaceEntrySchema = z\n .object({\n preset: z.string().min(1),\n rules: z.array(z.string().min(1)),\n })\n .strict();\n\nexport type WorkspaceEntry = z.infer<typeof WorkspaceEntrySchema>;\n\nexport const ManifestSchema = z\n .object({\n tools: z.array(z.string().min(1)).min(1),\n scope: z.enum(['project', 'global']),\n /** 비모노레포 단일 preset */\n preset: z.string().min(1).optional(),\n /** 모노레포: workspace path → { preset, rules } */\n workspaces: z.record(z.string(), WorkspaceEntrySchema).optional(),\n installed_rules: z.array(z.string().min(1)),\n /** SSOT 데이터 파일들의 deterministic SHA-256 해시 (6자리 hex). diff/update 판단 기준 */\n sourceHash: z.string().regex(/^[a-f0-9]{6}$/, 'sourceHash must be 6 lowercase hex chars'),\n generatedAt: z.string().datetime({ offset: true }),\n })\n .strict();\n\nexport type Manifest = z.infer<typeof ManifestSchema>;\n","import { readFileSync, readdirSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { parse } from 'yaml';\nimport { RuleSchema, PresetSchema } from './schemas/index.js';\nimport type { Rule, Preset } from './schemas/index.js';\n\n// priority 내림차순 정렬 (높을수록 상단 → U-shaped attention)\nexport const sortRulesByPriority = (rules: readonly Rule[]): Rule[] =>\n [...rules].sort((a, b) => b.priority - a.priority);\n\n// presets.yaml의 Record<id, {description, rules}> → Preset[] 변환\nexport const parseRawPresets = (raw: Record<string, { description: string; rules: string[] }>): Preset[] =>\n Object.entries(raw).map(([id, value]) => PresetSchema.parse({ id, ...value }));\n\n// TUI 세부조정: 사용자가 해제한 rule ID 목록을 제외 (순서 유지)\nexport const excludeRules = (rules: readonly Rule[], excludeIds: readonly string[]): Rule[] => {\n const excludeSet = new Set(excludeIds);\n return rules.filter((r) => !excludeSet.has(r.id));\n};\n\n// preset.rules ID 목록으로 allRules에서 필터링 + priority 정렬, 누락 시 throw\nexport const resolvePresetRules = (preset: Preset, allRules: readonly Rule[]): Rule[] => {\n const resolved = preset.rules.map((ruleId) => {\n const found = allRules.find((r) => r.id === ruleId);\n if (!found) throw new Error(`Rule not found: ${ruleId}`);\n return found;\n });\n return sortRulesByPriority(resolved);\n};\n\nexport const loadRuleFile = (filePath: string): Rule => {\n const raw = readFileSync(filePath, 'utf-8');\n return RuleSchema.parse(parse(raw));\n};\n\n// readdirSync + .yaml 필터 + sort\nexport const loadAllRules = (rulesDir: string): Rule[] => {\n const files = readdirSync(rulesDir)\n .filter((f) => f.endsWith('.yaml'))\n .sort();\n return files.map((f) => loadRuleFile(resolve(rulesDir, f)));\n};\n\nexport const loadPresets = (presetsPath: string): Preset[] => {\n const raw = readFileSync(presetsPath, 'utf-8');\n const data = parse(raw) as Record<string, { description: string; rules: string[] }>;\n return parseRawPresets(data);\n};\n","// Global 성격의 category (항상 로딩, frontmatter 없음)\nexport const GLOBAL_CATEGORIES = ['persona', 'communication', 'philosophy', 'convention', 'standard'] as const;\n\n// Claude Code paths: frontmatter용 Rule ID → glob 매핑\n// src/ 없이 루트를 src처럼 쓰는 React/Next.js 프로젝트 고려\n// 매핑에 없는 domain 룰 → frontmatter 없이 항상 로딩 (안전 fallback)\nexport const CLAUDE_CODE_PATH_GLOBS: Readonly<Record<string, readonly string[]>> = {\n typescript: ['**/*.ts', '**/*.tsx'],\n 'react-typescript': ['**/*.tsx', '**/*.jsx'],\n nextjs: ['**/app/**', 'next.config.*', '**/middleware.ts'],\n nestjs: ['**/*.module.ts', '**/*.controller.ts', '**/*.service.ts'],\n 'nestjs-graphql': ['**/*.resolver.ts'],\n graphql: ['**/*.graphql', '**/*.gql'],\n 'prisma-postgresql': ['prisma/**', '**/*.prisma'],\n 'shadcn-ui': ['**/components/ui/**'],\n flutter: ['lib/**/*.dart'],\n python: ['**/*.py'],\n fastapi: ['**/routers/**', '**/main.py'],\n sqlalchemy: ['**/models/**/*.py', 'alembic/**'],\n 'data-pipeline-python': ['**/pipelines/**', '**/etl/**'],\n 'ai-llm-python': ['**/agents/**', '**/chains/**'],\n 'libs-frontend-web': ['**/*.tsx', '**/*.ts'],\n 'libs-frontend-app': ['lib/**/*.dart'],\n 'libs-backend-ts': ['**/*.ts'],\n 'libs-backend-python': ['**/*.py'],\n};\n\nexport const TOOL_OUTPUT_MAP = {\n 'claude-code': {\n mode: 'multi-file' as const,\n rulesDir: '.claude/rules',\n fileExtension: '.md',\n contextStrategy: 'path-scoped' as const, // paths: frontmatter\n },\n codex: {\n mode: 'multi-file' as const,\n rootFileName: 'AGENTS.md', // global 룰\n domainFileName: 'AGENTS.override.md', // domain 룰 (하위 폴더)\n contextStrategy: 'hierarchical' as const, // 루트 + 하위 폴더 JIT\n },\n gemini: {\n mode: 'multi-file' as const,\n rootFileName: 'GEMINI.md', // global 룰\n domainFileName: 'GEMINI.md', // domain 룰 (하위 폴더)\n contextStrategy: 'hierarchical' as const, // 루트 + 하위 폴더 JIT\n },\n} as const;\n\nexport type ToolId = keyof typeof TOOL_OUTPUT_MAP;\n","import type { Rule, DecisionTableEntry } from './schemas/index.js';\nimport { GLOBAL_CATEGORIES, CLAUDE_CODE_PATH_GLOBS, TOOL_OUTPUT_MAP } from './tool-output.js';\nimport type { ToolId } from './tool-output.js';\n\n// \"react-typescript\" → \"React Typescript\"\nexport const ruleIdToTitle = (id: string): string =>\n id\n .split('-')\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(' ');\n\n// DecisionTableEntry[] → Markdown 테이블 (pipe 문자 &#124; escape)\nexport const renderDecisionTable = (entries: readonly DecisionTableEntry[]): string => {\n const escape = (s: string) => s.replace(/\\|/g, '&#124;');\n const hasAvoid = entries.some((e) => e.avoid !== undefined);\n\n const header = hasAvoid ? '| When | Then | Avoid |\\n|------|------|-------|' : '| When | Then |\\n|------|------|';\n\n const rows = entries.map((e) => {\n const when = escape(e.when);\n const then = escape(e.then);\n if (hasAvoid) {\n const avoid = e.avoid ? escape(e.avoid) : '';\n return `| ${when} | ${then} | ${avoid} |`;\n }\n return `| ${when} | ${then} |`;\n });\n\n return [header, ...rows].join('\\n');\n};\n\n// 단일 Rule → Markdown (빈 섹션 생략)\nexport const renderRuleToMarkdown = (rule: Rule): string => {\n const sections: string[] = [`# ${ruleIdToTitle(rule.id)}`];\n\n if (rule.content.constraints.length > 0) {\n sections.push('## Constraints');\n sections.push(rule.content.constraints.map((c) => `- ${c}`).join('\\n'));\n }\n\n if (rule.content.guidelines.length > 0) {\n sections.push('## Guidelines');\n sections.push(rule.content.guidelines.map((g) => `- ${g}`).join('\\n'));\n }\n\n if (rule.content.decision_table && rule.content.decision_table.length > 0) {\n sections.push('## Decision Table');\n sections.push(renderDecisionTable(rule.content.decision_table));\n }\n\n return sections.join('\\n\\n');\n};\n\n// Rule[] → 단일 Markdown (--- separator, single-file 모드용)\nexport const renderRulesToMarkdown = (rules: readonly Rule[]): string =>\n rules.map(renderRuleToMarkdown).join('\\n\\n---\\n\\n');\n\n// Rule이 global 카테고리에 속하는지 판별\nexport const isGlobalRule = (rule: Rule): boolean => (GLOBAL_CATEGORIES as readonly string[]).includes(rule.category);\n\n// Rule[] → { global, domain } 분리\nexport const partitionRules = (rules: readonly Rule[]): { global: Rule[]; domain: Rule[] } => {\n const global: Rule[] = [];\n const domain: Rule[] = [];\n for (const rule of rules) {\n if (isGlobalRule(rule)) {\n global.push(rule);\n } else {\n domain.push(rule);\n }\n }\n return { global, domain };\n};\n\n// glob 배열 → YAML frontmatter 블록\nexport const renderFrontmatter = (paths: readonly string[]): string => {\n const lines = paths.map((p) => ` - \"${p}\"`).join('\\n');\n return `---\\npaths:\\n${lines}\\n---`;\n};\n\n// 단일 Rule → Claude Code용 Markdown\n// domain 룰이면서 glob 매핑이 있으면 paths: frontmatter 추가\n// global 룰 또는 매핑 없는 domain 룰 → frontmatter 없음 (안전 fallback)\nexport const renderClaudeCodeRule = (rule: Rule): string => {\n const globs = CLAUDE_CODE_PATH_GLOBS[rule.id];\n if (!isGlobalRule(rule) && globs !== undefined) {\n return `${renderFrontmatter(globs)}\\n\\n${renderRuleToMarkdown(rule)}`;\n }\n return renderRuleToMarkdown(rule);\n};\n\n// 도구별 렌더링 결과 타입 (tagged union)\nexport type ClaudeCodeRenderResult = {\n tool: 'claude-code';\n files: { fileName: string; content: string }[];\n};\n\nexport type CodexRenderResult = {\n tool: 'codex';\n rootContent: string;\n domainContent: string;\n};\n\nexport type GeminiRenderResult = {\n tool: 'gemini';\n rootContent: string;\n domainContent: string;\n};\n\nexport type ToolRenderResult = ClaudeCodeRenderResult | CodexRenderResult | GeminiRenderResult;\n\n// CLI 진입점: toolId + rules → 도구별 렌더링 결과\nexport const renderForTool = (toolId: ToolId, rules: readonly Rule[]): ToolRenderResult => {\n const { global, domain } = partitionRules(rules);\n const config = TOOL_OUTPUT_MAP[toolId];\n\n if (toolId === 'claude-code') {\n const { fileExtension } = config as (typeof TOOL_OUTPUT_MAP)['claude-code'];\n const files = rules.map((rule) => ({\n fileName: `${rule.id}${fileExtension}`,\n content: renderClaudeCodeRule(rule),\n }));\n return { tool: 'claude-code', files };\n }\n\n const rootContent = renderRulesToMarkdown(global);\n const domainContent = renderRulesToMarkdown(domain);\n\n if (toolId === 'codex') {\n return { tool: 'codex', rootContent, domainContent };\n }\n\n // gemini\n return { tool: 'gemini', rootContent, domainContent };\n};\n","import { createHash } from 'node:crypto';\nimport { readFileSync, readdirSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { ManifestSchema } from './schemas/index.js';\nimport type { Manifest } from './schemas/index.js';\n\n// 문자열 배열 → SHA-256 → 6-hex (caller가 정렬 책임)\nexport const computeHash = (contents: readonly string[]): string =>\n createHash('sha256').update(contents.join('')).digest('hex').slice(0, 6);\n\n// rulesDir 내 YAML 파일들을 alphabetical 정렬 후 해싱\nexport const computeSourceHash = (rulesDir: string): string => {\n const files = readdirSync(rulesDir)\n .filter((f) => f.endsWith('.yaml'))\n .sort();\n const contents = files.map((f) => readFileSync(resolve(rulesDir, f), 'utf-8'));\n return computeHash(contents);\n};\n\n// Manifest Builder (Pure, 단 generatedAt에 현재 시각 사용)\nexport const buildManifest = (params: {\n tools: readonly string[];\n scope: 'project' | 'global';\n preset?: string;\n workspaces?: Record<string, { preset: string; rules: string[] }>;\n installedRules: readonly string[];\n sourceHash: string;\n}): Manifest =>\n ManifestSchema.parse({\n tools: [...params.tools],\n scope: params.scope,\n preset: params.preset,\n workspaces: params.workspaces,\n installed_rules: [...params.installedRules],\n sourceHash: params.sourceHash,\n generatedAt: new Date().toISOString(),\n });\n","const MANAGED_MARKER = '<!-- managed by ai-ops -->';\nconst META_PATTERN = /^<!-- sourceHash: ([a-f0-9]{6}) \\| generatedAt: (.+) -->$/;\n\nexport const wrapWithHeader = (content: string, meta: { sourceHash: string; generatedAt: string }): string => {\n const metaLine = `<!-- sourceHash: ${meta.sourceHash} | generatedAt: ${meta.generatedAt} -->`;\n return `${MANAGED_MARKER}\\n${metaLine}\\n\\n${content}`;\n};\n\nexport const isManagedFile = (content: string): boolean => content.startsWith(MANAGED_MARKER);\n\nexport const parseManagedHeader = (content: string): { sourceHash: string; generatedAt: string } | null => {\n if (!isManagedFile(content)) return null;\n\n const lines = content.split('\\n');\n const metaLine = lines[1] ?? '';\n const match = META_PATTERN.exec(metaLine);\n if (!match) return null;\n\n return { sourceHash: match[1], generatedAt: match[2] };\n};\n\nexport const stripManagedHeader = (content: string): string => {\n if (!isManagedFile(content)) return content;\n\n const lines = content.split('\\n');\n // marker line + meta line + blank line = 3 lines\n const stripped = lines.slice(3).join('\\n');\n return stripped;\n};\n","import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { ManifestSchema } from './schemas/index.js';\nimport type { Manifest } from './schemas/index.js';\n\nexport const MANIFEST_FILENAME = '.ai-ops-manifest.json';\n\n// Pure\nexport const parseManifest = (json: string): Manifest => ManifestSchema.parse(JSON.parse(json));\n\nexport const serializeManifest = (manifest: Manifest): string => JSON.stringify(manifest, null, 2) + '\\n';\n\n// I/O\nexport const resolveManifestPath = (basePath: string): string => join(basePath, MANIFEST_FILENAME);\n\nexport const readManifest = (manifestPath: string): Manifest | null => {\n let raw: string;\n try {\n raw = readFileSync(manifestPath, 'utf-8');\n } catch {\n return null;\n }\n return parseManifest(raw);\n};\n\nexport const writeManifest = (manifestPath: string, manifest: Manifest): void => {\n mkdirSync(dirname(manifestPath), { recursive: true });\n writeFileSync(manifestPath, serializeManifest(manifest), 'utf-8');\n};\n","import type { Manifest } from './schemas/index.js';\n\nexport type DiffResult = {\n status: 'up-to-date' | 'changed';\n added: readonly string[];\n removed: readonly string[];\n sourceChanged: boolean;\n};\n\nexport const computeDiff = (params: {\n previous: Manifest;\n currentRules: readonly string[];\n currentSourceHash: string;\n}): DiffResult => {\n const { previous, currentRules, currentSourceHash } = params;\n\n const previousSet = new Set(previous.installed_rules);\n const currentSet = new Set(currentRules);\n\n const added = currentRules.filter((id) => !previousSet.has(id));\n const removed = previous.installed_rules.filter((id) => !currentSet.has(id));\n const sourceChanged = previous.sourceHash !== currentSourceHash;\n\n const status = added.length > 0 || removed.length > 0 || sourceChanged ? 'changed' : 'up-to-date';\n\n return { status, added, removed, sourceChanged };\n};\n","import { join } from 'node:path';\nimport { wrapWithHeader } from './managed-header.js';\nimport { TOOL_OUTPUT_MAP } from './tool-output.js';\nimport type { ToolId } from './tool-output.js';\nimport type { ToolRenderResult } from './renderer.js';\n\nexport type FileAction = {\n relativePath: string;\n content: string;\n};\n\nexport const buildInstallPlan = (params: {\n toolId: ToolId;\n renderResult: ToolRenderResult;\n meta: { sourceHash: string; generatedAt: string };\n}): readonly FileAction[] => {\n const { toolId, renderResult, meta } = params;\n\n if (toolId === 'claude-code' && renderResult.tool === 'claude-code') {\n const { rulesDir } = TOOL_OUTPUT_MAP['claude-code'];\n return renderResult.files.map(({ fileName, content }) => ({\n relativePath: join(rulesDir, fileName),\n content: wrapWithHeader(content, meta),\n }));\n }\n\n if (\n (toolId === 'codex' && renderResult.tool === 'codex') ||\n (toolId === 'gemini' && renderResult.tool === 'gemini')\n ) {\n const config = TOOL_OUTPUT_MAP[toolId];\n const actions: FileAction[] = [];\n\n if (renderResult.rootContent) {\n actions.push({\n relativePath: config.rootFileName,\n content: wrapWithHeader(renderResult.rootContent, meta),\n });\n }\n\n if (renderResult.domainContent) {\n actions.push({\n relativePath: config.domainFileName,\n content: wrapWithHeader(renderResult.domainContent, meta),\n });\n }\n\n return actions;\n }\n\n return [];\n};\n","import { dirname, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n// dist/index.js 위치 기준 → 상위(패키지 루트) → data/\n// src/에서 실행 시: src/../data = data/ ✅\n// dist/에서 실행 시: dist/../data = data/ ✅\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nexport const COMPILER_DATA_DIR = resolve(__dirname, '..', 'data');\n"],"mappings":"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","names":["z","z","readFileSync","readdirSync","resolve","readdirSync","readFileSync","resolve","readFileSync","readFileSync","join","join","dirname","resolve"]}
1
+ {"version":3,"sources":["../src/schemas/rule.schema.ts","../src/schemas/preset.schema.ts","../src/schemas/manifest.schema.ts","../src/loader.ts","../src/renderer.ts","../src/tool-output.ts","../src/source-hash.ts","../src/managed-header.ts","../src/manifest-io.ts","../src/diff.ts","../src/install-plan.ts","../src/paths.ts"],"sourcesContent":["/**\n * Rule = SSOT의 최소 지식 단위. 하나의 코딩 컨벤션/아키텍처 규칙을 YAML로 구조화한 것.\n */\nimport { z } from 'zod';\n\nexport const DecisionTableEntrySchema = z\n .object({\n when: z.string().min(1),\n then: z.string().min(1),\n /** 조건부 규칙에서 회피해야 할 패턴 */\n avoid: z.string().min(1).optional(),\n })\n .strict();\n\nexport const RuleContentSchema = z\n .object({\n /** Anti-pattern 규칙 ('하지 마라'). guidelines보다 항상 상단 렌더링 */\n constraints: z.array(z.string().min(1)),\n /** Positive 규칙 ('해라') */\n guidelines: z.array(z.string().min(1)),\n /** 조건부 규칙. when→then→avoid 구조 */\n decision_table: z.array(DecisionTableEntrySchema).optional(),\n })\n .strict();\n\nexport const RuleSchema = z\n .object({\n id: z.string().regex(/^[a-z0-9]+(-[a-z0-9]+)*$/, 'id must be kebab-case'),\n category: z.string().min(1),\n tags: z.array(z.string().min(1)),\n /** 0-100. 높을수록 생성 파일 상단 배치 (U-shaped attention 최적화) */\n priority: z.number().int().min(0).max(100),\n content: RuleContentSchema,\n })\n .strict();\n\nexport type DecisionTableEntry = z.infer<typeof DecisionTableEntrySchema>;\nexport type RuleContent = z.infer<typeof RuleContentSchema>;\nexport type Rule = z.infer<typeof RuleSchema>;\n","import { z } from 'zod';\n\nexport const PresetSchema = z\n .object({\n id: z\n .string()\n .regex(/^[a-z][a-z0-9-]*$/)\n .min(1),\n description: z.string().min(1),\n rules: z.array(z.string().min(1)).min(1),\n })\n .strict();\n\nexport type Preset = z.infer<typeof PresetSchema>;\n","/**\n * Manifest = 설치 추적 메타데이터. CLI가 이전 설치 상태를 기억하기 위한 JSON.\n */\nimport { z } from 'zod';\n\nexport const SCOPES = {\n PROJECT: 'project',\n GLOBAL: 'global',\n} as const;\n\n/** 모노레포 워크스페이스별 preset + rules 추적 */\nconst WorkspaceEntrySchema = z\n .object({\n preset: z.string().min(1),\n rules: z.array(z.string().min(1)),\n })\n .strict();\n\nexport type WorkspaceEntry = z.infer<typeof WorkspaceEntrySchema>;\n\nexport const ManifestSchema = z\n .object({\n tools: z.array(z.string().min(1)).min(1),\n scope: z.enum(['project', 'global']),\n /** 비모노레포 단일 preset */\n preset: z.string().min(1).optional(),\n /** 모노레포: workspace path → { preset, rules } */\n workspaces: z.record(z.string(), WorkspaceEntrySchema).optional(),\n installed_rules: z.array(z.string().min(1)),\n /** SSOT 데이터 파일들의 deterministic SHA-256 해시 (6자리 hex). diff/update 판단 기준 */\n sourceHash: z.string().regex(/^[a-f0-9]{6}$/, 'sourceHash must be 6 lowercase hex chars'),\n generatedAt: z.string().datetime({ offset: true }),\n })\n .strict();\n\nexport type Manifest = z.infer<typeof ManifestSchema>;\n","import { readFileSync, readdirSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { parse } from 'yaml';\nimport { RuleSchema, PresetSchema } from './schemas/index.js';\nimport type { Rule, Preset } from './schemas/index.js';\n\n// priority 내림차순 정렬 (높을수록 상단 → U-shaped attention)\nexport const sortRulesByPriority = (rules: readonly Rule[]): Rule[] =>\n [...rules].sort((a, b) => b.priority - a.priority);\n\n// presets.yaml의 Record<id, {description, rules}> → Preset[] 변환\nexport const parseRawPresets = (raw: Record<string, { description: string; rules: string[] }>): Preset[] =>\n Object.entries(raw).map(([id, value]) => PresetSchema.parse({ id, ...value }));\n\n// TUI 세부조정: 사용자가 해제한 rule ID 목록을 제외 (순서 유지)\nexport const excludeRules = (rules: readonly Rule[], excludeIds: readonly string[]): Rule[] => {\n const excludeSet = new Set(excludeIds);\n return rules.filter((r) => !excludeSet.has(r.id));\n};\n\n// preset.rules ID 목록으로 allRules에서 필터링 + priority 정렬, 누락 시 throw\nexport const resolvePresetRules = (preset: Preset, allRules: readonly Rule[]): Rule[] => {\n const resolved = preset.rules.map((ruleId) => {\n const found = allRules.find((r) => r.id === ruleId);\n if (!found) throw new Error(`Rule not found: ${ruleId}`);\n return found;\n });\n return sortRulesByPriority(resolved);\n};\n\nexport const loadRuleFile = (filePath: string): Rule => {\n const raw = readFileSync(filePath, 'utf-8');\n return RuleSchema.parse(parse(raw));\n};\n\n// readdirSync + .yaml 필터 + sort\nexport const loadAllRules = (rulesDir: string): Rule[] => {\n const files = readdirSync(rulesDir)\n .filter((f) => f.endsWith('.yaml'))\n .sort();\n return files.map((f) => loadRuleFile(resolve(rulesDir, f)));\n};\n\nexport const loadPresets = (presetsPath: string): Preset[] => {\n const raw = readFileSync(presetsPath, 'utf-8');\n const data = parse(raw) as Record<string, { description: string; rules: string[] }>;\n return parseRawPresets(data);\n};\n","import { join } from 'node:path';\nimport type { Rule, DecisionTableEntry } from './schemas/index.js';\nimport { GLOBAL_CATEGORIES, CLAUDE_CODE_PATH_GLOBS, TOOL_OUTPUT_MAP } from './tool-output.js';\nimport type { ToolId } from './tool-output.js';\n\n// \"react-typescript\" → \"React Typescript\"\nexport const ruleIdToTitle = (id: string): string =>\n id\n .split('-')\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(' ');\n\n// DecisionTableEntry[] → Markdown 테이블 (pipe 문자 &#124; escape)\nexport const renderDecisionTable = (entries: readonly DecisionTableEntry[]): string => {\n const escape = (s: string) => s.replace(/\\|/g, '&#124;');\n const hasAvoid = entries.some((e) => e.avoid !== undefined);\n\n const header = hasAvoid ? '| When | Then | Avoid |\\n|------|------|-------|' : '| When | Then |\\n|------|------|';\n\n const rows = entries.map((e) => {\n const when = escape(e.when);\n const then = escape(e.then);\n if (hasAvoid) {\n const avoid = e.avoid ? escape(e.avoid) : '';\n return `| ${when} | ${then} | ${avoid} |`;\n }\n return `| ${when} | ${then} |`;\n });\n\n return [header, ...rows].join('\\n');\n};\n\n// 단일 Rule → Markdown (빈 섹션 생략)\nexport const renderRuleToMarkdown = (rule: Rule): string => {\n const sections: string[] = [`# ${ruleIdToTitle(rule.id)}`];\n\n if (rule.content.constraints.length > 0) {\n sections.push('## Constraints');\n sections.push(rule.content.constraints.map((c) => `- ${c}`).join('\\n'));\n }\n\n if (rule.content.guidelines.length > 0) {\n sections.push('## Guidelines');\n sections.push(rule.content.guidelines.map((g) => `- ${g}`).join('\\n'));\n }\n\n if (rule.content.decision_table && rule.content.decision_table.length > 0) {\n sections.push('## Decision Table');\n sections.push(renderDecisionTable(rule.content.decision_table));\n }\n\n return sections.join('\\n\\n');\n};\n\n// Rule[] → 단일 Markdown (--- separator, single-file 모드용)\nexport const renderRulesToMarkdown = (rules: readonly Rule[]): string =>\n rules.map(renderRuleToMarkdown).join('\\n\\n---\\n\\n');\n\n// Rule이 global 카테고리에 속하는지 판별\nexport const isGlobalRule = (rule: Rule): boolean => (GLOBAL_CATEGORIES as readonly string[]).includes(rule.category);\n\n// Rule[] → { global, domain } 분리\nexport const partitionRules = (rules: readonly Rule[]): { global: Rule[]; domain: Rule[] } => {\n const global: Rule[] = [];\n const domain: Rule[] = [];\n for (const rule of rules) {\n if (isGlobalRule(rule)) {\n global.push(rule);\n } else {\n domain.push(rule);\n }\n }\n return { global, domain };\n};\n\n// glob 배열 → YAML frontmatter 블록\nexport const renderFrontmatter = (paths: readonly string[]): string => {\n const lines = paths.map((p) => ` - \"${p}\"`).join('\\n');\n return `---\\npaths:\\n${lines}\\n---`;\n};\n\nexport type WorkspaceMapping = {\n path: string;\n ruleIds: readonly string[];\n};\n\n// 단일 Rule → Claude Code용 Markdown\n// domain 룰이면서 glob 매핑이 있으면 paths: frontmatter 추가 (단일 프로젝트 전용)\n// global 룰 또는 매핑 없는 domain 룰 → frontmatter 없음\nexport const renderClaudeCodeRule = (rule: Rule): string => {\n const globs = CLAUDE_CODE_PATH_GLOBS[rule.id];\n if (!isGlobalRule(rule) && globs !== undefined) {\n return `${renderFrontmatter(globs)}\\n\\n${renderRuleToMarkdown(rule)}`;\n }\n return renderRuleToMarkdown(rule);\n};\n\n// 도구별 렌더링 결과 타입 (tagged union)\nexport type ClaudeCodeRenderResult = {\n tool: 'claude-code';\n files: { relativePath: string; content: string }[];\n};\n\nexport type CodexRenderResult = {\n tool: 'codex';\n rootContent: string;\n domainContent: string;\n};\n\nexport type GeminiRenderResult = {\n tool: 'gemini';\n rootContent: string;\n domainContent: string;\n};\n\nexport type ToolRenderResult = ClaudeCodeRenderResult | CodexRenderResult | GeminiRenderResult;\n\n// CLI 진입점: toolId + rules → 도구별 렌더링 결과\nexport const renderForTool = (\n toolId: ToolId,\n rules: readonly Rule[],\n workspaceMappings?: readonly WorkspaceMapping[],\n): ToolRenderResult => {\n const config = TOOL_OUTPUT_MAP[toolId];\n\n if (toolId === 'claude-code') {\n const { rulesDir, fileExtension } = config as (typeof TOOL_OUTPUT_MAP)['claude-code'];\n\n if (!workspaceMappings || workspaceMappings.length === 0) {\n // 단일 프로젝트: domain 룰에 paths: frontmatter (path-scoped)\n const files = rules.map((rule) => ({\n relativePath: join(rulesDir, `${rule.id}${fileExtension}`),\n content: renderClaudeCodeRule(rule),\n }));\n return { tool: 'claude-code', files };\n }\n\n // 모노레포: global → .claude/rules/, domain → {workspace}/CLAUDE.md (진짜 지연 로딩)\n const { global, domain } = partitionRules(rules);\n\n const globalFiles = global.map((rule) => ({\n relativePath: join(rulesDir, `${rule.id}${fileExtension}`),\n content: renderRuleToMarkdown(rule), // global은 frontmatter 불필요\n }));\n\n const workspaceFiles: { relativePath: string; content: string }[] = [];\n for (const ws of workspaceMappings) {\n const wsRules = domain.filter((r) => ws.ruleIds.includes(r.id));\n if (wsRules.length === 0) continue;\n workspaceFiles.push({\n relativePath: join(ws.path, 'CLAUDE.md'),\n content: renderRulesToMarkdown(wsRules),\n });\n }\n\n return { tool: 'claude-code', files: [...globalFiles, ...workspaceFiles] };\n }\n\n const { global, domain } = partitionRules(rules);\n const rootContent = renderRulesToMarkdown(global);\n const domainContent = renderRulesToMarkdown(domain);\n\n if (toolId === 'codex') {\n return { tool: 'codex', rootContent, domainContent };\n }\n\n // gemini\n return { tool: 'gemini', rootContent, domainContent };\n};\n","// Global 성격의 category (항상 로딩, frontmatter 없음)\nexport const GLOBAL_CATEGORIES = ['persona', 'communication', 'philosophy', 'convention', 'standard'] as const;\n\n// Claude Code paths: frontmatter용 Rule ID → glob 매핑\n// src/ 없이 루트를 src처럼 쓰는 React/Next.js 프로젝트 고려\n// 매핑에 없는 domain 룰 → frontmatter 없이 항상 로딩 (안전 fallback)\nexport const CLAUDE_CODE_PATH_GLOBS: Readonly<Record<string, readonly string[]>> = {\n typescript: ['**/*.ts', '**/*.tsx'],\n 'react-typescript': ['**/*.tsx', '**/*.jsx'],\n nextjs: ['**/app/**', 'next.config.*', '**/middleware.ts'],\n nestjs: ['**/*.module.ts', '**/*.controller.ts', '**/*.service.ts'],\n 'nestjs-graphql': ['**/*.resolver.ts'],\n graphql: ['**/*.graphql', '**/*.gql'],\n 'prisma-postgresql': ['prisma/**', '**/*.prisma'],\n 'shadcn-ui': ['**/components/ui/**'],\n flutter: ['lib/**/*.dart'],\n python: ['**/*.py'],\n fastapi: ['**/routers/**', '**/main.py'],\n sqlalchemy: ['**/models/**/*.py', 'alembic/**'],\n 'data-pipeline-python': ['**/pipelines/**', '**/etl/**'],\n 'ai-llm-python': ['**/agents/**', '**/chains/**'],\n 'libs-frontend-web': ['**/*.tsx', '**/*.ts'],\n 'libs-frontend-app': ['lib/**/*.dart'],\n 'libs-backend-ts': ['**/*.ts'],\n 'libs-backend-python': ['**/*.py'],\n};\n\nexport const TOOL_OUTPUT_MAP = {\n 'claude-code': {\n mode: 'multi-file' as const,\n rulesDir: '.claude/rules',\n fileExtension: '.md',\n // single: path-scoped (paths: frontmatter) / monorepo: hierarchical ({workspace}/CLAUDE.md)\n contextStrategy: 'hybrid' as const,\n },\n codex: {\n mode: 'multi-file' as const,\n dir: '.codex',\n rootFileName: 'AGENTS.md', // global 룰\n domainFileName: 'AGENTS.override.md', // domain 룰 (하위 폴더)\n contextStrategy: 'hierarchical' as const, // 루트 + 하위 폴더 JIT\n },\n gemini: {\n mode: 'multi-file' as const,\n dir: '.gemini',\n rootFileName: 'GEMINI.md', // global 룰\n domainFileName: 'GEMINI.md', // domain 룰 (하위 폴더)\n contextStrategy: 'hierarchical' as const, // 루트 + 하위 폴더 JIT\n },\n} as const;\n\nexport type ToolId = keyof typeof TOOL_OUTPUT_MAP;\n","import { createHash } from 'node:crypto';\nimport { readFileSync, readdirSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { ManifestSchema } from './schemas/index.js';\nimport type { Manifest } from './schemas/index.js';\n\n// 문자열 배열 → SHA-256 → 6-hex (caller가 정렬 책임)\nexport const computeHash = (contents: readonly string[]): string =>\n createHash('sha256').update(contents.join('')).digest('hex').slice(0, 6);\n\n// rulesDir 내 YAML 파일들을 alphabetical 정렬 후 해싱\nexport const computeSourceHash = (rulesDir: string): string => {\n const files = readdirSync(rulesDir)\n .filter((f) => f.endsWith('.yaml'))\n .sort();\n const contents = files.map((f) => readFileSync(resolve(rulesDir, f), 'utf-8'));\n return computeHash(contents);\n};\n\n// Manifest Builder (Pure, 단 generatedAt에 현재 시각 사용)\nexport const buildManifest = (params: {\n tools: readonly string[];\n scope: 'project' | 'global';\n preset?: string;\n workspaces?: Record<string, { preset: string; rules: string[] }>;\n installedRules: readonly string[];\n sourceHash: string;\n}): Manifest =>\n ManifestSchema.parse({\n tools: [...params.tools],\n scope: params.scope,\n preset: params.preset,\n workspaces: params.workspaces,\n installed_rules: [...params.installedRules],\n sourceHash: params.sourceHash,\n generatedAt: new Date().toISOString(),\n });\n","const MANAGED_MARKER = '<!-- managed by ai-ops -->';\nconst META_PATTERN = /^<!-- sourceHash: ([a-f0-9]{6}) \\| generatedAt: (.+) -->$/;\n\nexport const wrapWithHeader = (content: string, meta: { sourceHash: string; generatedAt: string }): string => {\n const metaLine = `<!-- sourceHash: ${meta.sourceHash} | generatedAt: ${meta.generatedAt} -->`;\n return `${MANAGED_MARKER}\\n${metaLine}\\n\\n${content}`;\n};\n\nexport const isManagedFile = (content: string): boolean => content.startsWith(MANAGED_MARKER);\n\nexport const parseManagedHeader = (content: string): { sourceHash: string; generatedAt: string } | null => {\n if (!isManagedFile(content)) return null;\n\n const lines = content.split('\\n');\n const metaLine = lines[1] ?? '';\n const match = META_PATTERN.exec(metaLine);\n if (!match) return null;\n\n return { sourceHash: match[1], generatedAt: match[2] };\n};\n\nexport const stripManagedHeader = (content: string): string => {\n if (!isManagedFile(content)) return content;\n\n const lines = content.split('\\n');\n // marker line + meta line + blank line = 3 lines\n const stripped = lines.slice(3).join('\\n');\n return stripped;\n};\n","import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { ManifestSchema } from './schemas/index.js';\nimport type { Manifest } from './schemas/index.js';\n\nexport const MANIFEST_FILENAME = '.ai-ops-manifest.json';\n\n// Pure\nexport const parseManifest = (json: string): Manifest => ManifestSchema.parse(JSON.parse(json));\n\nexport const serializeManifest = (manifest: Manifest): string => JSON.stringify(manifest, null, 2) + '\\n';\n\n// I/O\nexport const resolveManifestPath = (basePath: string): string => join(basePath, MANIFEST_FILENAME);\n\nexport const readManifest = (manifestPath: string): Manifest | null => {\n let raw: string;\n try {\n raw = readFileSync(manifestPath, 'utf-8');\n } catch {\n return null;\n }\n return parseManifest(raw);\n};\n\nexport const writeManifest = (manifestPath: string, manifest: Manifest): void => {\n mkdirSync(dirname(manifestPath), { recursive: true });\n writeFileSync(manifestPath, serializeManifest(manifest), 'utf-8');\n};\n","import type { Manifest } from './schemas/index.js';\n\nexport type DiffResult = {\n status: 'up-to-date' | 'changed';\n added: readonly string[];\n removed: readonly string[];\n sourceChanged: boolean;\n};\n\nexport const computeDiff = (params: {\n previous: Manifest;\n currentRules: readonly string[];\n currentSourceHash: string;\n}): DiffResult => {\n const { previous, currentRules, currentSourceHash } = params;\n\n const previousSet = new Set(previous.installed_rules);\n const currentSet = new Set(currentRules);\n\n const added = currentRules.filter((id) => !previousSet.has(id));\n const removed = previous.installed_rules.filter((id) => !currentSet.has(id));\n const sourceChanged = previous.sourceHash !== currentSourceHash;\n\n const status = added.length > 0 || removed.length > 0 || sourceChanged ? 'changed' : 'up-to-date';\n\n return { status, added, removed, sourceChanged };\n};\n","import { join } from 'node:path';\nimport { wrapWithHeader } from './managed-header.js';\nimport { TOOL_OUTPUT_MAP } from './tool-output.js';\nimport type { ToolId } from './tool-output.js';\nimport type { ToolRenderResult } from './renderer.js';\n\nexport type FileAction = {\n relativePath: string;\n content: string;\n};\n\nexport const buildInstallPlan = (params: {\n toolId: ToolId;\n renderResult: ToolRenderResult;\n meta: { sourceHash: string; generatedAt: string };\n}): readonly FileAction[] => {\n const { toolId, renderResult, meta } = params;\n\n if (toolId === 'claude-code' && renderResult.tool === 'claude-code') {\n return renderResult.files.map(({ relativePath, content }) => ({\n relativePath,\n content: wrapWithHeader(content, meta),\n }));\n }\n\n if (\n (toolId === 'codex' && renderResult.tool === 'codex') ||\n (toolId === 'gemini' && renderResult.tool === 'gemini')\n ) {\n const config = TOOL_OUTPUT_MAP[toolId];\n const actions: FileAction[] = [];\n\n if (renderResult.rootContent) {\n actions.push({\n relativePath: join(config.dir, config.rootFileName),\n content: wrapWithHeader(renderResult.rootContent, meta),\n });\n }\n\n if (renderResult.domainContent) {\n actions.push({\n relativePath: join(config.dir, config.domainFileName),\n content: wrapWithHeader(renderResult.domainContent, meta),\n });\n }\n\n return actions;\n }\n\n return [];\n};\n","import { dirname, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n// dist/index.js 위치 기준 → 상위(패키지 루트) → data/\n// src/에서 실행 시: src/../data = data/ ✅\n// dist/에서 실행 시: dist/../data = data/ ✅\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nexport const COMPILER_DATA_DIR = resolve(__dirname, '..', 'data');\n"],"mappings":"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","names":["z","z","global","domain","readFileSync","readdirSync","resolve","readdirSync","readFileSync","resolve","readFileSync","join","join","readFileSync","join","join","dirname","resolve"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-ops-compiler",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Compiler and rule management core for ai-ops scaffolding tools",
5
5
  "license": "MIT",
6
6
  "type": "module",