ai-ops-cli 0.1.9 → 0.1.10

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/bin/index.js CHANGED
@@ -5,39 +5,438 @@ import { Command } from "commander";
5
5
 
6
6
  // src/commands/init.ts
7
7
  import * as p2 from "@clack/prompts";
8
+ import { join as join8 } from "path";
9
+
10
+ // src/core/schemas/rule.schema.ts
11
+ import { z } from "zod";
12
+ var DecisionTableEntrySchema = z.object({
13
+ when: z.string().min(1),
14
+ then: z.string().min(1),
15
+ /** 조건부 규칙에서 회피해야 할 패턴 */
16
+ avoid: z.string().min(1).optional()
17
+ }).strict();
18
+ var RuleContentSchema = z.object({
19
+ /** Anti-pattern 규칙 ('하지 마라'). guidelines보다 항상 상단 렌더링 */
20
+ constraints: z.array(z.string().min(1)),
21
+ /** Positive 규칙 ('해라') */
22
+ guidelines: z.array(z.string().min(1)),
23
+ /** 조건부 규칙. when→then→avoid 구조 */
24
+ decision_table: z.array(DecisionTableEntrySchema).optional()
25
+ }).strict();
26
+ var RuleSchema = z.object({
27
+ id: z.string().regex(/^[a-z0-9]+(-[a-z0-9]+)*$/, "id must be kebab-case"),
28
+ category: z.string().min(1),
29
+ tags: z.array(z.string().min(1)),
30
+ /** 0-100. 높을수록 생성 파일 상단 배치 (U-shaped attention 최적화) */
31
+ priority: z.number().int().min(0).max(100),
32
+ content: RuleContentSchema
33
+ }).strict();
34
+
35
+ // src/core/schemas/preset.schema.ts
36
+ import { z as z2 } from "zod";
37
+ var PresetSchema = z2.object({
38
+ id: z2.string().regex(/^[a-z][a-z0-9-]*$/).min(1),
39
+ description: z2.string().min(1),
40
+ rules: z2.array(z2.string().min(1)).min(1)
41
+ }).strict();
42
+
43
+ // src/core/schemas/manifest.schema.ts
44
+ import { z as z3 } from "zod";
45
+ var WorkspaceEntrySchema = z3.object({
46
+ preset: z3.string().min(1),
47
+ rules: z3.array(z3.string().min(1))
48
+ }).strict();
49
+ var ManifestSchema = z3.object({
50
+ tools: z3.array(z3.string().min(1)).min(1),
51
+ scope: z3.literal("project"),
52
+ /** 비모노레포 단일 preset */
53
+ preset: z3.string().min(1).optional(),
54
+ /** 모노레포: workspace path → { preset, rules } */
55
+ workspaces: z3.record(z3.string(), WorkspaceEntrySchema).optional(),
56
+ installed_rules: z3.array(z3.string().min(1)),
57
+ /** 실제 디스크에 쓰여진 파일 상대 경로 목록 (uninstall용). 기존 manifest 호환성 위해 optional */
58
+ installed_files: z3.array(z3.string().min(1)).optional(),
59
+ /** non-managed 파일에 섹션을 append한 경우 추적 (uninstall 시 섹션만 제거) */
60
+ appended_files: z3.array(z3.string().min(1)).optional(),
61
+ /** SSOT 데이터 파일들의 deterministic SHA-256 해시 (6자리 hex). diff/update 판단 기준 */
62
+ sourceHash: z3.string().regex(/^[a-f0-9]{6}$/, "sourceHash must be 6 lowercase hex chars"),
63
+ generatedAt: z3.string().datetime({ offset: true })
64
+ }).strict();
65
+
66
+ // src/core/loader.ts
67
+ import { readFileSync, readdirSync } from "fs";
68
+ import { resolve } from "path";
69
+ import { parse } from "yaml";
70
+ var sortRulesByPriority = (rules) => [...rules].sort((a, b) => b.priority - a.priority);
71
+ var parseRawPresets = (raw) => Object.entries(raw).map(([id, value]) => PresetSchema.parse({ id, ...value }));
72
+ var excludeRules = (rules, excludeIds) => {
73
+ const excludeSet = new Set(excludeIds);
74
+ return rules.filter((r) => !excludeSet.has(r.id));
75
+ };
76
+ var resolvePresetRules = (preset, allRules) => {
77
+ const resolved = preset.rules.map((ruleId) => {
78
+ const found = allRules.find((r) => r.id === ruleId);
79
+ if (!found) throw new Error(`Rule not found: ${ruleId}`);
80
+ return found;
81
+ });
82
+ return sortRulesByPriority(resolved);
83
+ };
84
+ var loadRuleFile = (filePath) => {
85
+ const raw = readFileSync(filePath, "utf-8");
86
+ return RuleSchema.parse(parse(raw));
87
+ };
88
+ var loadAllRules = (rulesDir) => {
89
+ const files = readdirSync(rulesDir).filter((f) => f.endsWith(".yaml")).sort();
90
+ return files.map((f) => loadRuleFile(resolve(rulesDir, f)));
91
+ };
92
+ var loadPresets = (presetsPath) => {
93
+ const raw = readFileSync(presetsPath, "utf-8");
94
+ const data = parse(raw);
95
+ return parseRawPresets(data);
96
+ };
97
+
98
+ // src/core/renderer.ts
99
+ import { join } from "path";
100
+
101
+ // src/core/tool-output.ts
102
+ var GLOBAL_CATEGORIES = ["persona", "communication", "philosophy", "convention", "standard"];
103
+ var CLAUDE_CODE_PATH_GLOBS = {
104
+ typescript: ["**/*.ts", "**/*.tsx"],
105
+ "react-typescript": ["**/*.tsx", "**/*.jsx"],
106
+ nextjs: ["**/app/**", "next.config.*", "**/middleware.ts"],
107
+ nestjs: ["**/*.module.ts", "**/*.controller.ts", "**/*.service.ts"],
108
+ "nestjs-graphql": ["**/*.resolver.ts"],
109
+ graphql: ["**/*.graphql", "**/*.gql"],
110
+ "prisma-postgresql": ["prisma/**", "**/*.prisma"],
111
+ "shadcn-ui": ["**/components/ui/**"],
112
+ flutter: ["lib/**/*.dart"],
113
+ python: ["**/*.py"],
114
+ fastapi: ["**/routers/**", "**/main.py"],
115
+ sqlalchemy: ["**/models/**/*.py", "alembic/**"],
116
+ "data-pipeline-python": ["**/pipelines/**", "**/etl/**"],
117
+ "ai-llm-python": ["**/agents/**", "**/chains/**"],
118
+ "libs-frontend-web": ["**/*.tsx", "**/*.ts"],
119
+ "libs-frontend-app": ["lib/**/*.dart"],
120
+ "libs-backend-ts": ["**/*.ts"],
121
+ "libs-backend-python": ["**/*.py"]
122
+ };
123
+ var TOOL_OUTPUT_MAP = {
124
+ "claude-code": {
125
+ mode: "multi-file",
126
+ rulesDir: ".claude/rules",
127
+ fileExtension: ".md",
128
+ // single: path-scoped (paths: frontmatter) / monorepo: hierarchical ({workspace}/CLAUDE.md)
129
+ contextStrategy: "hybrid"
130
+ },
131
+ codex: {
132
+ mode: "multi-file",
133
+ dir: "",
134
+ rootFileName: "AGENTS.md",
135
+ // global 룰
136
+ domainFileName: "AGENTS.override.md",
137
+ // domain 룰 (하위 폴더)
138
+ contextStrategy: "hierarchical"
139
+ // 루트 + 하위 폴더 JIT
140
+ },
141
+ gemini: {
142
+ mode: "multi-file",
143
+ dir: ".gemini",
144
+ rootFileName: "GEMINI.md",
145
+ // global 룰
146
+ domainFileName: "GEMINI.md",
147
+ // domain 룰 (하위 폴더)
148
+ contextStrategy: "hierarchical"
149
+ // 루트 + 하위 폴더 JIT
150
+ }
151
+ };
152
+
153
+ // src/core/renderer.ts
154
+ var ruleIdToTitle = (id) => id.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
155
+ var renderDecisionTable = (entries) => {
156
+ const escape = (s) => s.replace(/\|/g, "|");
157
+ const hasAvoid = entries.some((e) => e.avoid !== void 0);
158
+ const header = hasAvoid ? "| When | Then | Avoid |\n|------|------|-------|" : "| When | Then |\n|------|------|";
159
+ const rows = entries.map((e) => {
160
+ const when = escape(e.when);
161
+ const then = escape(e.then);
162
+ if (hasAvoid) {
163
+ const avoid = e.avoid ? escape(e.avoid) : "";
164
+ return `| ${when} | ${then} | ${avoid} |`;
165
+ }
166
+ return `| ${when} | ${then} |`;
167
+ });
168
+ return [header, ...rows].join("\n");
169
+ };
170
+ var renderRuleToMarkdown = (rule) => {
171
+ const sections = [`# ${ruleIdToTitle(rule.id)}`];
172
+ if (rule.content.constraints.length > 0) {
173
+ sections.push("## Constraints");
174
+ sections.push(rule.content.constraints.map((c) => `- ${c}`).join("\n"));
175
+ }
176
+ if (rule.content.guidelines.length > 0) {
177
+ sections.push("## Guidelines");
178
+ sections.push(rule.content.guidelines.map((g) => `- ${g}`).join("\n"));
179
+ }
180
+ if (rule.content.decision_table && rule.content.decision_table.length > 0) {
181
+ sections.push("## Decision Table");
182
+ sections.push(renderDecisionTable(rule.content.decision_table));
183
+ }
184
+ return sections.join("\n\n");
185
+ };
186
+ var renderRulesToMarkdown = (rules) => rules.map(renderRuleToMarkdown).join("\n\n---\n\n");
187
+ var isGlobalRule = (rule) => GLOBAL_CATEGORIES.includes(rule.category);
188
+ var partitionRules = (rules) => {
189
+ const global = [];
190
+ const domain = [];
191
+ for (const rule of rules) {
192
+ if (isGlobalRule(rule)) {
193
+ global.push(rule);
194
+ } else {
195
+ domain.push(rule);
196
+ }
197
+ }
198
+ return { global, domain };
199
+ };
200
+ var renderFrontmatter = (paths) => {
201
+ const lines = paths.map((p6) => ` - "${p6}"`).join("\n");
202
+ return `---
203
+ paths:
204
+ ${lines}
205
+ ---`;
206
+ };
207
+ var renderClaudeCodeRule = (rule) => {
208
+ const globs = CLAUDE_CODE_PATH_GLOBS[rule.id];
209
+ if (!isGlobalRule(rule) && globs !== void 0) {
210
+ return `${renderFrontmatter(globs)}
211
+
212
+ ${renderRuleToMarkdown(rule)}`;
213
+ }
214
+ return renderRuleToMarkdown(rule);
215
+ };
216
+ var renderForTool = (toolId, rules, workspaceMappings) => {
217
+ const config = TOOL_OUTPUT_MAP[toolId];
218
+ if (toolId === "claude-code") {
219
+ const { rulesDir, fileExtension } = config;
220
+ if (!workspaceMappings || workspaceMappings.length === 0) {
221
+ const files = rules.map((rule) => ({
222
+ relativePath: join(rulesDir, `${rule.id}${fileExtension}`),
223
+ content: renderClaudeCodeRule(rule)
224
+ }));
225
+ return { tool: "claude-code", files };
226
+ }
227
+ const { global: global2, domain: domain2 } = partitionRules(rules);
228
+ const globalFiles = global2.map((rule) => ({
229
+ relativePath: join(rulesDir, `${rule.id}${fileExtension}`),
230
+ content: renderRuleToMarkdown(rule)
231
+ // global은 frontmatter 불필요
232
+ }));
233
+ const workspaceFiles = [];
234
+ for (const ws of workspaceMappings) {
235
+ const wsRules = domain2.filter((r) => ws.ruleIds.includes(r.id));
236
+ if (wsRules.length === 0) continue;
237
+ workspaceFiles.push({
238
+ relativePath: join(ws.path, "CLAUDE.md"),
239
+ content: renderRulesToMarkdown(wsRules)
240
+ });
241
+ }
242
+ return { tool: "claude-code", files: [...globalFiles, ...workspaceFiles] };
243
+ }
244
+ const { global, domain } = partitionRules(rules);
245
+ const rootContent = renderRulesToMarkdown(global);
246
+ const domainContent = renderRulesToMarkdown(domain);
247
+ if (toolId === "codex") {
248
+ return { tool: "codex", rootContent, domainContent };
249
+ }
250
+ return { tool: "gemini", rootContent, domainContent };
251
+ };
252
+
253
+ // src/core/source-hash.ts
254
+ import { createHash } from "crypto";
255
+ import { readFileSync as readFileSync2, readdirSync as readdirSync2 } from "fs";
256
+ import { resolve as resolve2 } from "path";
257
+ var computeHash = (contents) => createHash("sha256").update(contents.join("")).digest("hex").slice(0, 6);
258
+ var computeSourceHash = (rulesDir) => {
259
+ const files = readdirSync2(rulesDir).filter((f) => f.endsWith(".yaml")).sort();
260
+ const contents = files.map((f) => readFileSync2(resolve2(rulesDir, f), "utf-8"));
261
+ return computeHash(contents);
262
+ };
263
+ var buildManifest = (params) => ManifestSchema.parse({
264
+ tools: [...params.tools],
265
+ scope: params.scope,
266
+ preset: params.preset,
267
+ workspaces: params.workspaces,
268
+ installed_rules: [...params.installedRules],
269
+ installed_files: params.installedFiles ? [...params.installedFiles] : void 0,
270
+ appended_files: params.appendedFiles && params.appendedFiles.length > 0 ? [...params.appendedFiles] : void 0,
271
+ sourceHash: params.sourceHash,
272
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString()
273
+ });
274
+
275
+ // src/core/managed-header.ts
276
+ var MANAGED_MARKER = "<!-- managed by ai-ops -->";
277
+ var SECTION_START = "<!-- ai-ops:start -->";
278
+ var SECTION_END = "<!-- ai-ops:end -->";
279
+ var wrapWithHeader = (content, meta) => {
280
+ const metaLine = `<!-- sourceHash: ${meta.sourceHash} | generatedAt: ${meta.generatedAt} -->`;
281
+ return `${MANAGED_MARKER}
282
+ ${metaLine}
283
+
284
+ ${content}`;
285
+ };
286
+ var isManagedFile = (content) => content.startsWith(MANAGED_MARKER);
287
+ var stripManagedHeader = (content) => {
288
+ if (!isManagedFile(content)) return content;
289
+ const lines = content.split("\n");
290
+ const stripped = lines.slice(3).join("\n");
291
+ return stripped;
292
+ };
293
+ var wrapWithSection = (content, meta) => {
294
+ const metaLine = `<!-- sourceHash: ${meta.sourceHash} | generatedAt: ${meta.generatedAt} -->`;
295
+ return `${SECTION_START}
296
+ ${metaLine}
297
+
298
+ ${content}
299
+ ${SECTION_END}`;
300
+ };
301
+ var hasAiOpsSection = (content) => content.includes(SECTION_START) && content.includes(SECTION_END);
302
+ var stripAiOpsSection = (content) => {
303
+ const startIdx = content.indexOf(SECTION_START);
304
+ const endIdx = content.indexOf(SECTION_END);
305
+ if (startIdx === -1 || endIdx === -1) return content;
306
+ const before = content.slice(0, startIdx).trimEnd();
307
+ const after = content.slice(endIdx + SECTION_END.length).trimStart();
308
+ return before + (after ? "\n\n" + after : "") + "\n";
309
+ };
310
+ var replaceAiOpsSection = (existing, newSection) => {
311
+ const startIdx = existing.indexOf(SECTION_START);
312
+ const endIdx = existing.indexOf(SECTION_END);
313
+ if (startIdx === -1 || endIdx === -1) return existing;
314
+ const before = existing.slice(0, startIdx).trimEnd();
315
+ const after = existing.slice(endIdx + SECTION_END.length).trimStart();
316
+ return before + "\n\n" + newSection + (after ? "\n\n" + after : "") + "\n";
317
+ };
318
+
319
+ // src/core/manifest-io.ts
320
+ import { mkdirSync, readFileSync as readFileSync3, writeFileSync } from "fs";
321
+ import { dirname, join as join2 } from "path";
322
+ var MANIFEST_FILENAME = ".ai-ops-manifest.json";
323
+ var parseManifest = (json) => ManifestSchema.parse(JSON.parse(json));
324
+ var serializeManifest = (manifest) => JSON.stringify(manifest, null, 2) + "\n";
325
+ var resolveManifestPath = (basePath) => join2(basePath, MANIFEST_FILENAME);
326
+ var readManifest = (manifestPath) => {
327
+ let raw;
328
+ try {
329
+ raw = readFileSync3(manifestPath, "utf-8");
330
+ } catch {
331
+ return null;
332
+ }
333
+ return parseManifest(raw);
334
+ };
335
+ var writeManifest = (manifestPath, manifest) => {
336
+ mkdirSync(dirname(manifestPath), { recursive: true });
337
+ writeFileSync(manifestPath, serializeManifest(manifest), "utf-8");
338
+ };
339
+
340
+ // src/core/diff.ts
341
+ var computeDiff = (params) => {
342
+ const { previous, currentRules, currentSourceHash } = params;
343
+ const previousSet = new Set(previous.installed_rules);
344
+ const currentSet = new Set(currentRules);
345
+ const added = currentRules.filter((id) => !previousSet.has(id));
346
+ const removed = previous.installed_rules.filter((id) => !currentSet.has(id));
347
+ const sourceChanged = previous.sourceHash !== currentSourceHash;
348
+ const status = added.length > 0 || removed.length > 0 || sourceChanged ? "changed" : "up-to-date";
349
+ return { status, added, removed, sourceChanged };
350
+ };
351
+
352
+ // src/core/install-plan.ts
353
+ import { join as join3 } from "path";
354
+ var CODEX_PLAN_SECTION = "\n\n---\n\n## Plan\n\nSave plans to `.codex/plans/<timestamp>-<topic>.md` when creating or updating plans in plan mode.";
355
+ var buildInstallPlan = (params) => {
356
+ const { toolId, renderResult, meta } = params;
357
+ if (toolId === "claude-code" && renderResult.tool === "claude-code") {
358
+ return renderResult.files.map(({ relativePath, content }) => ({
359
+ relativePath,
360
+ content: wrapWithHeader(content, meta)
361
+ }));
362
+ }
363
+ if (toolId === "codex" && renderResult.tool === "codex" || toolId === "gemini" && renderResult.tool === "gemini") {
364
+ const config = TOOL_OUTPUT_MAP[toolId];
365
+ const actions = [];
366
+ if (renderResult.rootContent) {
367
+ const rootContent = toolId === "codex" ? renderResult.rootContent + CODEX_PLAN_SECTION : renderResult.rootContent;
368
+ actions.push({
369
+ relativePath: join3(config.dir, config.rootFileName),
370
+ content: wrapWithHeader(rootContent, meta)
371
+ });
372
+ }
373
+ if (renderResult.domainContent) {
374
+ actions.push({
375
+ relativePath: join3(config.dir, config.domainFileName),
376
+ content: wrapWithHeader(renderResult.domainContent, meta)
377
+ });
378
+ }
379
+ return actions;
380
+ }
381
+ return [];
382
+ };
383
+
384
+ // src/core/uninstall-plan.ts
8
385
  import { join as join4 } from "path";
9
- import {
10
- loadAllRules,
11
- loadPresets,
12
- resolvePresetRules,
13
- excludeRules,
14
- isGlobalRule,
15
- partitionRules,
16
- renderForTool,
17
- renderRulesToMarkdown,
18
- buildInstallPlan,
19
- buildManifest,
20
- computeSourceHash,
21
- resolveManifestPath,
22
- writeManifest,
23
- wrapWithHeader,
24
- TOOL_OUTPUT_MAP
25
- } from "ai-ops-compiler";
386
+ var inferInstalledFiles = (manifest) => {
387
+ const files = [];
388
+ const isMonorepo = manifest.workspaces !== void 0;
389
+ for (const toolId of manifest.tools) {
390
+ if (toolId === "claude-code") {
391
+ const config = TOOL_OUTPUT_MAP["claude-code"];
392
+ for (const ruleId of manifest.installed_rules) {
393
+ files.push(join4(config.rulesDir, `${ruleId}${config.fileExtension}`));
394
+ }
395
+ } else if (toolId === "codex") {
396
+ const config = TOOL_OUTPUT_MAP["codex"];
397
+ if (!isMonorepo) {
398
+ files.push(join4(config.dir, config.rootFileName));
399
+ files.push(join4(config.dir, config.domainFileName));
400
+ } else {
401
+ files.push(join4(config.dir, config.rootFileName));
402
+ for (const ws of Object.keys(manifest.workspaces ?? {})) {
403
+ files.push(join4(ws, config.domainFileName));
404
+ }
405
+ }
406
+ } else if (toolId === "gemini") {
407
+ const config = TOOL_OUTPUT_MAP["gemini"];
408
+ if (!isMonorepo) {
409
+ files.push(join4(config.dir, config.rootFileName));
410
+ } else {
411
+ files.push(join4(config.dir, config.rootFileName));
412
+ for (const ws of Object.keys(manifest.workspaces ?? {})) {
413
+ files.push(join4(ws, config.domainFileName));
414
+ }
415
+ }
416
+ }
417
+ }
418
+ return [...new Set(files)];
419
+ };
420
+
421
+ // src/core/paths.ts
422
+ import { dirname as dirname2, resolve as resolve3 } from "path";
423
+ import { fileURLToPath } from "url";
424
+ var __dirname = dirname2(fileURLToPath(import.meta.url));
425
+ var COMPILER_DATA_DIR = resolve3(__dirname, "..", "..", "data");
26
426
 
27
427
  // src/lib/paths.ts
28
- import { join } from "path";
29
- import { COMPILER_DATA_DIR } from "ai-ops-compiler";
30
- var resolveRulesDir = () => join(COMPILER_DATA_DIR, "rules");
31
- var resolvePresetsPath = () => join(COMPILER_DATA_DIR, "presets.yaml");
428
+ import { join as join5 } from "path";
429
+ var resolveRulesDir = () => join5(COMPILER_DATA_DIR, "rules");
430
+ var resolvePresetsPath = () => join5(COMPILER_DATA_DIR, "presets.yaml");
32
431
  var resolveBasePath = () => process.cwd();
33
432
 
34
433
  // src/lib/workspace.ts
35
- import { existsSync, readdirSync, statSync } from "fs";
36
- import { join as join2, resolve } from "path";
434
+ import { existsSync, readdirSync as readdirSync3, statSync } from "fs";
435
+ import { join as join6, resolve as resolve4 } from "path";
37
436
  var EXCLUDE_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", ".next", ".turbo", ".cache", "coverage"]);
38
437
  var isVisibleDir = (basePath, name) => {
39
438
  if (name.startsWith(".") || EXCLUDE_DIRS.has(name)) return false;
40
- return statSync(resolve(basePath, name)).isDirectory();
439
+ return statSync(resolve4(basePath, name)).isDirectory();
41
440
  };
42
441
  var PROJECT_MANIFESTS = [
43
442
  "package.json",
@@ -53,20 +452,20 @@ var PROJECT_MANIFESTS = [
53
452
  "go.mod"
54
453
  // Go
55
454
  ];
56
- var isWorkspaceRoot = (dirPath) => PROJECT_MANIFESTS.some((f) => existsSync(join2(dirPath, f)));
455
+ var isWorkspaceRoot = (dirPath) => PROJECT_MANIFESTS.some((f) => existsSync(join6(dirPath, f)));
57
456
  var listWorkspaceCandidates = (basePath) => {
58
- const topLevel = readdirSync(basePath).filter((name) => isVisibleDir(basePath, name));
457
+ const topLevel = readdirSync3(basePath).filter((name) => isVisibleDir(basePath, name));
59
458
  const candidates = [];
60
459
  for (const dir of topLevel) {
61
- const subPath = resolve(basePath, dir);
460
+ const subPath = resolve4(basePath, dir);
62
461
  if (isWorkspaceRoot(subPath)) {
63
462
  candidates.push(dir);
64
463
  } else {
65
- const children = readdirSync(subPath).filter((name) => isVisibleDir(subPath, name));
66
- const wsChildren = children.filter((name) => isWorkspaceRoot(resolve(subPath, name)));
464
+ const children = readdirSync3(subPath).filter((name) => isVisibleDir(subPath, name));
465
+ const wsChildren = children.filter((name) => isWorkspaceRoot(resolve4(subPath, name)));
67
466
  if (wsChildren.length > 0) {
68
467
  for (const child of wsChildren) {
69
- candidates.push(join2(dir, child));
468
+ candidates.push(join6(dir, child));
70
469
  }
71
470
  } else {
72
471
  candidates.push(dir);
@@ -77,40 +476,33 @@ var listWorkspaceCandidates = (basePath) => {
77
476
  };
78
477
 
79
478
  // src/lib/install.ts
80
- import { existsSync as existsSync2, mkdirSync, readFileSync, writeFileSync } from "fs";
81
- import { dirname, resolve as resolve2 } from "path";
82
- import {
83
- isManagedFile,
84
- hasAiOpsSection,
85
- wrapWithSection,
86
- replaceAiOpsSection,
87
- stripManagedHeader
88
- } from "ai-ops-compiler";
479
+ import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "fs";
480
+ import { dirname as dirname3, resolve as resolve5 } from "path";
89
481
  var installFiles = (basePath, actions, meta) => {
90
482
  const written = [];
91
483
  const appended = [];
92
484
  const skipped = [];
93
485
  for (const action of actions) {
94
- const absPath = resolve2(basePath, action.relativePath);
486
+ const absPath = resolve5(basePath, action.relativePath);
95
487
  if (existsSync2(absPath)) {
96
- const existing = readFileSync(absPath, "utf-8");
488
+ const existing = readFileSync4(absPath, "utf-8");
97
489
  if (isManagedFile(existing)) {
98
- writeFileSync(absPath, action.content, "utf-8");
490
+ writeFileSync2(absPath, action.content, "utf-8");
99
491
  written.push(action.relativePath);
100
492
  } else if (hasAiOpsSection(existing)) {
101
493
  const sectionContent = wrapWithSection(stripManagedHeader(action.content), meta);
102
494
  const updated = replaceAiOpsSection(existing, sectionContent);
103
- writeFileSync(absPath, updated, "utf-8");
495
+ writeFileSync2(absPath, updated, "utf-8");
104
496
  appended.push(action.relativePath);
105
497
  } else {
106
498
  const sectionContent = wrapWithSection(stripManagedHeader(action.content), meta);
107
499
  const updated = existing.trimEnd() + "\n\n" + sectionContent + "\n";
108
- writeFileSync(absPath, updated, "utf-8");
500
+ writeFileSync2(absPath, updated, "utf-8");
109
501
  appended.push(action.relativePath);
110
502
  }
111
503
  } else {
112
- mkdirSync(dirname(absPath), { recursive: true });
113
- writeFileSync(absPath, action.content, "utf-8");
504
+ mkdirSync2(dirname3(absPath), { recursive: true });
505
+ writeFileSync2(absPath, action.content, "utf-8");
114
506
  written.push(action.relativePath);
115
507
  }
116
508
  }
@@ -119,8 +511,8 @@ var installFiles = (basePath, actions, meta) => {
119
511
 
120
512
  // src/lib/gemini-settings.ts
121
513
  import * as p from "@clack/prompts";
122
- import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
123
- import { join as join3 } from "path";
514
+ import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
515
+ import { join as join7 } from "path";
124
516
  var SETTING_GROUPS = [
125
517
  {
126
518
  value: "ui",
@@ -179,12 +571,12 @@ var promptGeminiSettings = async () => {
179
571
  };
180
572
  var installGeminiSettings = (basePath, selectedValues) => {
181
573
  if (selectedValues.length === 0) return;
182
- const settingsDir = join3(basePath, ".gemini");
183
- const settingsPath = join3(settingsDir, "settings.json");
574
+ const settingsDir = join7(basePath, ".gemini");
575
+ const settingsPath = join7(settingsDir, "settings.json");
184
576
  let existing = {};
185
577
  if (existsSync3(settingsPath)) {
186
578
  try {
187
- existing = JSON.parse(readFileSync2(settingsPath, "utf-8"));
579
+ existing = JSON.parse(readFileSync5(settingsPath, "utf-8"));
188
580
  } catch {
189
581
  }
190
582
  }
@@ -194,8 +586,8 @@ var installGeminiSettings = (basePath, selectedValues) => {
194
586
  if (!group) continue;
195
587
  merged = deepMerge(merged, group.patch);
196
588
  }
197
- mkdirSync2(settingsDir, { recursive: true });
198
- writeFileSync2(settingsPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
589
+ mkdirSync3(settingsDir, { recursive: true });
590
+ writeFileSync3(settingsPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
199
591
  };
200
592
 
201
593
  // src/commands/init.ts
@@ -249,7 +641,7 @@ var installHierarchicalMonorepo = (toolId, mappings, basePath, meta) => {
249
641
  const { global } = partitionRules(allRules);
250
642
  if (global.length > 0) {
251
643
  const rootAction = {
252
- relativePath: join4(config.dir, config.rootFileName),
644
+ relativePath: join8(config.dir, config.rootFileName),
253
645
  content: wrapWithHeader(renderRulesToMarkdown(global), meta)
254
646
  };
255
647
  const r = installFiles(basePath, [rootAction], meta);
@@ -260,7 +652,7 @@ var installHierarchicalMonorepo = (toolId, mappings, basePath, meta) => {
260
652
  const { domain } = partitionRules(mapping.finalRules);
261
653
  if (domain.length === 0) continue;
262
654
  const domainAction = {
263
- relativePath: join4(mapping.workspace, config.domainFileName),
655
+ relativePath: join8(mapping.workspace, config.domainFileName),
264
656
  content: wrapWithHeader(renderRulesToMarkdown(domain), meta)
265
657
  };
266
658
  const r = installFiles(basePath, [domainAction], meta);
@@ -387,25 +779,10 @@ ${allAppended.map((f) => ` ${f}`).join("\n")}`);
387
779
 
388
780
  // src/commands/update.ts
389
781
  import * as p3 from "@clack/prompts";
390
- import {
391
- readManifest,
392
- resolveManifestPath as resolveManifestPath2,
393
- loadAllRules as loadAllRules2,
394
- renderForTool as renderForTool2,
395
- buildInstallPlan as buildInstallPlan2,
396
- buildManifest as buildManifest2,
397
- writeManifest as writeManifest2,
398
- computeSourceHash as computeSourceHash2,
399
- computeDiff,
400
- partitionRules as partitionRules2,
401
- renderRulesToMarkdown as renderRulesToMarkdown2,
402
- wrapWithHeader as wrapWithHeader2,
403
- TOOL_OUTPUT_MAP as TOOL_OUTPUT_MAP2
404
- } from "ai-ops-compiler";
405
- import { join as join5 } from "path";
782
+ import { join as join9 } from "path";
406
783
  var updateCommand = async (opts) => {
407
784
  const basePath = resolveBasePath();
408
- const manifestPath = resolveManifestPath2(basePath);
785
+ const manifestPath = resolveManifestPath(basePath);
409
786
  p3.intro("ai-ops update");
410
787
  const manifest = readManifest(manifestPath);
411
788
  if (!manifest) {
@@ -413,7 +790,7 @@ var updateCommand = async (opts) => {
413
790
  process.exit(1);
414
791
  }
415
792
  const rulesDir = resolveRulesDir();
416
- const sourceHash = computeSourceHash2(rulesDir);
793
+ const sourceHash = computeSourceHash(rulesDir);
417
794
  const diffResult = computeDiff({
418
795
  previous: manifest,
419
796
  currentRules: manifest.installed_rules,
@@ -426,7 +803,7 @@ var updateCommand = async (opts) => {
426
803
  }
427
804
  const s = p3.spinner();
428
805
  s.start("\uADDC\uCE59 \uAC31\uC2E0 \uC911...");
429
- const allRules = loadAllRules2(rulesDir);
806
+ const allRules = loadAllRules(rulesDir);
430
807
  const meta = { sourceHash, generatedAt: (/* @__PURE__ */ new Date()).toISOString() };
431
808
  const allInstalledFiles = [];
432
809
  const allAppended = [];
@@ -441,20 +818,20 @@ var updateCommand = async (opts) => {
441
818
  path,
442
819
  ruleIds: entry.rules
443
820
  }));
444
- const renderResult = renderForTool2("claude-code", rulesToInstall, workspaceMappings);
445
- const actions = buildInstallPlan2({ toolId: "claude-code", renderResult, meta });
821
+ const renderResult = renderForTool("claude-code", rulesToInstall, workspaceMappings);
822
+ const actions = buildInstallPlan({ toolId: "claude-code", renderResult, meta });
446
823
  const r = installFiles(basePath, actions, meta);
447
824
  allInstalledFiles.push(...r.written);
448
825
  allAppended.push(...r.appended);
449
826
  } else {
450
- const config = TOOL_OUTPUT_MAP2[toolId];
827
+ const config = TOOL_OUTPUT_MAP[toolId];
451
828
  const allInstalledRuleSet = new Set(manifest.installed_rules);
452
829
  const allRulesToInstall = allRules.filter((r) => allInstalledRuleSet.has(r.id));
453
- const { global } = partitionRules2(allRulesToInstall);
830
+ const { global } = partitionRules(allRulesToInstall);
454
831
  if (global.length > 0) {
455
832
  const rootAction = {
456
- relativePath: join5(config.dir, config.rootFileName),
457
- content: wrapWithHeader2(renderRulesToMarkdown2(global), meta)
833
+ relativePath: join9(config.dir, config.rootFileName),
834
+ content: wrapWithHeader(renderRulesToMarkdown(global), meta)
458
835
  };
459
836
  const r = installFiles(basePath, [rootAction], meta);
460
837
  allInstalledFiles.push(...r.written);
@@ -463,11 +840,11 @@ var updateCommand = async (opts) => {
463
840
  for (const [ws, entry] of workspaceEntries) {
464
841
  const wsRuleSet = new Set(entry.rules);
465
842
  const wsRules = allRules.filter((r2) => wsRuleSet.has(r2.id));
466
- const { domain } = partitionRules2(wsRules);
843
+ const { domain } = partitionRules(wsRules);
467
844
  if (domain.length === 0) continue;
468
845
  const domainAction = {
469
- relativePath: join5(ws, config.domainFileName),
470
- content: wrapWithHeader2(renderRulesToMarkdown2(domain), meta)
846
+ relativePath: join9(ws, config.domainFileName),
847
+ content: wrapWithHeader(renderRulesToMarkdown(domain), meta)
471
848
  };
472
849
  const r = installFiles(basePath, [domainAction], meta);
473
850
  allInstalledFiles.push(...r.written);
@@ -480,14 +857,14 @@ var updateCommand = async (opts) => {
480
857
  const rulesToInstall = allRules.filter((r) => installedRuleSet.has(r.id));
481
858
  for (const toolIdStr of manifest.tools) {
482
859
  const toolId = toolIdStr;
483
- const renderResult = renderForTool2(toolId, rulesToInstall);
484
- const actions = buildInstallPlan2({ toolId, renderResult, meta });
860
+ const renderResult = renderForTool(toolId, rulesToInstall);
861
+ const actions = buildInstallPlan({ toolId, renderResult, meta });
485
862
  const r = installFiles(basePath, actions, meta);
486
863
  allInstalledFiles.push(...r.written);
487
864
  allAppended.push(...r.appended);
488
865
  }
489
866
  }
490
- const newManifest = buildManifest2({
867
+ const newManifest = buildManifest({
491
868
  tools: manifest.tools,
492
869
  scope: manifest.scope,
493
870
  preset: manifest.preset,
@@ -497,24 +874,23 @@ var updateCommand = async (opts) => {
497
874
  appendedFiles: allAppended.length > 0 ? allAppended : manifest.appended_files,
498
875
  sourceHash
499
876
  });
500
- writeManifest2(manifestPath, newManifest);
877
+ writeManifest(manifestPath, newManifest);
501
878
  s.stop("\uADDC\uCE59 \uAC31\uC2E0 \uC644\uB8CC");
502
879
  p3.outro("ai-ops update \uC644\uB8CC");
503
880
  };
504
881
 
505
882
  // src/commands/diff.ts
506
883
  import * as p4 from "@clack/prompts";
507
- import { readManifest as readManifest2, resolveManifestPath as resolveManifestPath3, computeSourceHash as computeSourceHash3, computeDiff as computeDiff2 } from "ai-ops-compiler";
508
884
  var diffCommand = async () => {
509
885
  const basePath = resolveBasePath();
510
886
  p4.intro("ai-ops diff");
511
- const manifest = readManifest2(resolveManifestPath3(basePath));
887
+ const manifest = readManifest(resolveManifestPath(basePath));
512
888
  if (!manifest) {
513
889
  p4.log.error("manifest\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. \uBA3C\uC800 ai-ops init\uC744 \uC2E4\uD589\uD558\uC138\uC694.");
514
890
  process.exit(1);
515
891
  }
516
- const sourceHash = computeSourceHash3(resolveRulesDir());
517
- const result = computeDiff2({
892
+ const sourceHash = computeSourceHash(resolveRulesDir());
893
+ const result = computeDiff({
518
894
  previous: manifest,
519
895
  currentRules: manifest.installed_rules,
520
896
  currentSourceHash: sourceHash
@@ -538,28 +914,26 @@ var diffCommand = async () => {
538
914
  // src/commands/uninstall.ts
539
915
  import * as p5 from "@clack/prompts";
540
916
  import { rmSync as rmSync2 } from "fs";
541
- import { readManifest as readManifest3, resolveManifestPath as resolveManifestPath4, inferInstalledFiles, MANIFEST_FILENAME } from "ai-ops-compiler";
542
917
 
543
918
  // src/lib/uninstall.ts
544
- import { existsSync as existsSync4, readFileSync as readFileSync3, rmSync, readdirSync as readdirSync2, writeFileSync as writeFileSync3 } from "fs";
545
- import { resolve as resolve3, dirname as dirname2 } from "path";
546
- import { isManagedFile as isManagedFile2, hasAiOpsSection as hasAiOpsSection2, stripAiOpsSection } from "ai-ops-compiler";
919
+ import { existsSync as existsSync4, readFileSync as readFileSync6, rmSync, readdirSync as readdirSync4, writeFileSync as writeFileSync4 } from "fs";
920
+ import { resolve as resolve6, dirname as dirname4 } from "path";
547
921
  var removeFiles = (basePath, relativePaths) => {
548
922
  const deleted = [];
549
923
  const cleaned = [];
550
924
  const skipped = [];
551
925
  const notFound = [];
552
926
  for (const rel of relativePaths) {
553
- const absPath = resolve3(basePath, rel);
927
+ const absPath = resolve6(basePath, rel);
554
928
  if (!existsSync4(absPath)) {
555
929
  notFound.push(rel);
556
930
  continue;
557
931
  }
558
- const content = readFileSync3(absPath, "utf-8");
559
- if (!isManagedFile2(content)) {
560
- if (hasAiOpsSection2(content)) {
932
+ const content = readFileSync6(absPath, "utf-8");
933
+ if (!isManagedFile(content)) {
934
+ if (hasAiOpsSection(content)) {
561
935
  const stripped = stripAiOpsSection(content);
562
- writeFileSync3(absPath, stripped, "utf-8");
936
+ writeFileSync4(absPath, stripped, "utf-8");
563
937
  cleaned.push(rel);
564
938
  } else {
565
939
  skipped.push(rel);
@@ -574,10 +948,10 @@ var removeFiles = (basePath, relativePaths) => {
574
948
  var cleanEmptyDirs = (basePath, dirs) => {
575
949
  const removed = [];
576
950
  for (const dir of dirs) {
577
- const absDir = resolve3(basePath, dir);
951
+ const absDir = resolve6(basePath, dir);
578
952
  if (!existsSync4(absDir)) continue;
579
953
  try {
580
- const entries = readdirSync2(absDir);
954
+ const entries = readdirSync4(absDir);
581
955
  if (entries.length === 0) {
582
956
  rmSync(absDir, { recursive: true });
583
957
  removed.push(dir);
@@ -590,7 +964,7 @@ var cleanEmptyDirs = (basePath, dirs) => {
590
964
  var collectManagedDirs = (relativePaths) => {
591
965
  const dirs = /* @__PURE__ */ new Set();
592
966
  for (const rel of relativePaths) {
593
- const dir = dirname2(rel);
967
+ const dir = dirname4(rel);
594
968
  if (dir !== ".") {
595
969
  dirs.add(dir);
596
970
  }
@@ -601,9 +975,9 @@ var collectManagedDirs = (relativePaths) => {
601
975
  // src/commands/uninstall.ts
602
976
  var uninstallCommand = async () => {
603
977
  const basePath = resolveBasePath();
604
- const manifestPath = resolveManifestPath4(basePath);
978
+ const manifestPath = resolveManifestPath(basePath);
605
979
  p5.intro("ai-ops uninstall");
606
- const manifest = readManifest3(manifestPath);
980
+ const manifest = readManifest(manifestPath);
607
981
  if (!manifest) {
608
982
  p5.log.error("manifest\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. \uBA3C\uC800 ai-ops init\uC744 \uC2E4\uD589\uD558\uC138\uC694.");
609
983
  process.exit(1);