ai-ops-cli 0.1.15 → 0.1.16
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 +316 -145
- package/dist/bin/index.js.map +1 -1
- package/package.json +1 -1
package/dist/bin/index.js
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
import { Command } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/commands/init.ts
|
|
7
|
-
import * as
|
|
8
|
-
import { join as
|
|
7
|
+
import * as p4 from "@clack/prompts";
|
|
8
|
+
import { join as join10 } from "path";
|
|
9
9
|
|
|
10
10
|
// src/core/schemas/rule.schema.ts
|
|
11
11
|
import { z } from "zod";
|
|
@@ -44,7 +44,8 @@ var PresetSchema = z2.object({
|
|
|
44
44
|
import { z as z3 } from "zod";
|
|
45
45
|
var SettingsConfigSchema = z3.object({
|
|
46
46
|
claude: z3.array(z3.string().min(1)).optional(),
|
|
47
|
-
gemini: z3.array(z3.string().min(1)).optional()
|
|
47
|
+
gemini: z3.array(z3.string().min(1)).optional(),
|
|
48
|
+
prettierignore: z3.boolean().optional()
|
|
48
49
|
}).strict();
|
|
49
50
|
var WorkspaceEntrySchema = z3.object({
|
|
50
51
|
preset: z3.string().min(1),
|
|
@@ -239,7 +240,7 @@ var partitionRules = (rules) => {
|
|
|
239
240
|
return { global, domain };
|
|
240
241
|
};
|
|
241
242
|
var renderFrontmatter = (paths) => {
|
|
242
|
-
const lines = paths.map((
|
|
243
|
+
const lines = paths.map((p8) => ` - "${p8}"`).join("\n");
|
|
243
244
|
return `---
|
|
244
245
|
paths:
|
|
245
246
|
${lines}
|
|
@@ -333,20 +334,7 @@ var buildManifest = (params) => ManifestSchema.parse({
|
|
|
333
334
|
var MANAGED_MARKER = "<!-- managed by ai-ops -->";
|
|
334
335
|
var SECTION_START = "<!-- ai-ops:start -->";
|
|
335
336
|
var SECTION_END = "<!-- ai-ops:end -->";
|
|
336
|
-
var
|
|
337
|
-
const metaLine = `<!-- sourceHash: ${meta.sourceHash} | generatedAt: ${meta.generatedAt} -->`;
|
|
338
|
-
return `${MANAGED_MARKER}
|
|
339
|
-
${metaLine}
|
|
340
|
-
|
|
341
|
-
${content}`;
|
|
342
|
-
};
|
|
343
|
-
var isManagedFile = (content) => content.startsWith(MANAGED_MARKER);
|
|
344
|
-
var stripManagedHeader = (content) => {
|
|
345
|
-
if (!isManagedFile(content)) return content;
|
|
346
|
-
const lines = content.split("\n");
|
|
347
|
-
const stripped = lines.slice(3).join("\n");
|
|
348
|
-
return stripped;
|
|
349
|
-
};
|
|
337
|
+
var hasLegacyHeader = (content) => content.includes(MANAGED_MARKER);
|
|
350
338
|
var wrapWithSection = (content, meta) => {
|
|
351
339
|
const metaLine = `<!-- sourceHash: ${meta.sourceHash} | generatedAt: ${meta.generatedAt} -->`;
|
|
352
340
|
return `${SECTION_START}
|
|
@@ -370,7 +358,7 @@ var replaceAiOpsSection = (existing, newSection) => {
|
|
|
370
358
|
if (startIdx === -1 || endIdx === -1) return existing;
|
|
371
359
|
const before = existing.slice(0, startIdx).trimEnd();
|
|
372
360
|
const after = existing.slice(endIdx + SECTION_END.length).trimStart();
|
|
373
|
-
return before
|
|
361
|
+
return [before, newSection, after].filter(Boolean).join("\n\n") + "\n";
|
|
374
362
|
};
|
|
375
363
|
|
|
376
364
|
// src/core/manifest-io.ts
|
|
@@ -415,7 +403,7 @@ var buildInstallPlan = (params) => {
|
|
|
415
403
|
if (toolId === "claude-code" && renderResult.tool === "claude-code") {
|
|
416
404
|
return renderResult.files.map(({ relativePath, content }) => ({
|
|
417
405
|
relativePath,
|
|
418
|
-
content:
|
|
406
|
+
content: wrapWithSection(content, meta)
|
|
419
407
|
}));
|
|
420
408
|
}
|
|
421
409
|
if (toolId === "codex" && renderResult.tool === "codex" || toolId === "gemini" && renderResult.tool === "gemini") {
|
|
@@ -425,13 +413,13 @@ var buildInstallPlan = (params) => {
|
|
|
425
413
|
const rootContent = toolId === "codex" ? renderResult.rootContent + CODEX_PLAN_SECTION : renderResult.rootContent;
|
|
426
414
|
actions.push({
|
|
427
415
|
relativePath: join3(config.dir, config.rootFileName),
|
|
428
|
-
content:
|
|
416
|
+
content: wrapWithSection(rootContent, meta)
|
|
429
417
|
});
|
|
430
418
|
}
|
|
431
419
|
if (renderResult.domainContent) {
|
|
432
420
|
actions.push({
|
|
433
421
|
relativePath: join3(config.dir, config.domainFileName),
|
|
434
|
-
content:
|
|
422
|
+
content: wrapWithSection(renderResult.domainContent, meta)
|
|
435
423
|
});
|
|
436
424
|
}
|
|
437
425
|
return actions;
|
|
@@ -536,32 +524,31 @@ var listWorkspaceCandidates = (basePath) => {
|
|
|
536
524
|
// src/lib/install.ts
|
|
537
525
|
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "fs";
|
|
538
526
|
import { dirname as dirname4, resolve as resolve5 } from "path";
|
|
539
|
-
var installFiles = (basePath, actions,
|
|
527
|
+
var installFiles = (basePath, actions, _meta) => {
|
|
540
528
|
const written = [];
|
|
541
529
|
const appended = [];
|
|
542
530
|
const skipped = [];
|
|
543
531
|
for (const action of actions) {
|
|
544
532
|
const absPath = resolve5(basePath, action.relativePath);
|
|
545
|
-
if (existsSync2(absPath)) {
|
|
533
|
+
if (!existsSync2(absPath)) {
|
|
534
|
+
mkdirSync2(dirname4(absPath), { recursive: true });
|
|
535
|
+
writeFileSync2(absPath, action.content + "\n", "utf-8");
|
|
536
|
+
written.push(action.relativePath);
|
|
537
|
+
} else {
|
|
546
538
|
const existing = readFileSync4(absPath, "utf-8");
|
|
547
|
-
if (
|
|
548
|
-
|
|
549
|
-
written.push(action.relativePath);
|
|
550
|
-
} else if (hasAiOpsSection(existing)) {
|
|
551
|
-
const sectionContent = wrapWithSection(stripManagedHeader(action.content), meta);
|
|
552
|
-
const updated = replaceAiOpsSection(existing, sectionContent);
|
|
539
|
+
if (hasAiOpsSection(existing)) {
|
|
540
|
+
const updated = replaceAiOpsSection(existing, action.content);
|
|
553
541
|
writeFileSync2(absPath, updated, "utf-8");
|
|
554
|
-
|
|
542
|
+
const stripped = stripAiOpsSection(existing);
|
|
543
|
+
(stripped.trim().length > 0 ? appended : written).push(action.relativePath);
|
|
544
|
+
} else if (hasLegacyHeader(existing)) {
|
|
545
|
+
writeFileSync2(absPath, action.content + "\n", "utf-8");
|
|
546
|
+
written.push(action.relativePath);
|
|
555
547
|
} else {
|
|
556
|
-
const
|
|
557
|
-
const updated = existing.trimEnd() + "\n\n" + sectionContent + "\n";
|
|
548
|
+
const updated = existing.trimEnd() + "\n\n" + action.content + "\n";
|
|
558
549
|
writeFileSync2(absPath, updated, "utf-8");
|
|
559
550
|
appended.push(action.relativePath);
|
|
560
551
|
}
|
|
561
|
-
} else {
|
|
562
|
-
mkdirSync2(dirname4(absPath), { recursive: true });
|
|
563
|
-
writeFileSync2(absPath, action.content, "utf-8");
|
|
564
|
-
written.push(action.relativePath);
|
|
565
552
|
}
|
|
566
553
|
}
|
|
567
554
|
return { written, appended, skipped };
|
|
@@ -569,8 +556,40 @@ var installFiles = (basePath, actions, meta) => {
|
|
|
569
556
|
|
|
570
557
|
// src/lib/gemini-settings.ts
|
|
571
558
|
import * as p from "@clack/prompts";
|
|
572
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
559
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync5, rmSync, writeFileSync as writeFileSync3 } from "fs";
|
|
573
560
|
import { join as join7 } from "path";
|
|
561
|
+
|
|
562
|
+
// src/lib/deep-merge.util.ts
|
|
563
|
+
var deepMerge = (base, patch) => {
|
|
564
|
+
const result = { ...base };
|
|
565
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
566
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value) && typeof result[key] === "object" && result[key] !== null && !Array.isArray(result[key])) {
|
|
567
|
+
result[key] = deepMerge(result[key], value);
|
|
568
|
+
} else {
|
|
569
|
+
result[key] = value;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
return result;
|
|
573
|
+
};
|
|
574
|
+
var deepRemoveKeys = (base, patch) => {
|
|
575
|
+
const result = { ...base };
|
|
576
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
577
|
+
if (!(key in result)) continue;
|
|
578
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value) && typeof result[key] === "object" && result[key] !== null && !Array.isArray(result[key])) {
|
|
579
|
+
const nested = deepRemoveKeys(result[key], value);
|
|
580
|
+
if (Object.keys(nested).length === 0) {
|
|
581
|
+
delete result[key];
|
|
582
|
+
} else {
|
|
583
|
+
result[key] = nested;
|
|
584
|
+
}
|
|
585
|
+
} else {
|
|
586
|
+
delete result[key];
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
return result;
|
|
590
|
+
};
|
|
591
|
+
|
|
592
|
+
// src/lib/gemini-settings.ts
|
|
574
593
|
var SETTING_GROUPS = [
|
|
575
594
|
{
|
|
576
595
|
value: "ui",
|
|
@@ -597,17 +616,6 @@ var SETTING_GROUPS = [
|
|
|
597
616
|
patch: { experimental: { jitContext: true, plan: true } }
|
|
598
617
|
}
|
|
599
618
|
];
|
|
600
|
-
var deepMerge = (base, patch) => {
|
|
601
|
-
const result = { ...base };
|
|
602
|
-
for (const [key, value] of Object.entries(patch)) {
|
|
603
|
-
if (value !== null && typeof value === "object" && !Array.isArray(value) && typeof result[key] === "object" && result[key] !== null) {
|
|
604
|
-
result[key] = deepMerge(result[key], value);
|
|
605
|
-
} else {
|
|
606
|
-
result[key] = value;
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
return result;
|
|
610
|
-
};
|
|
611
619
|
var promptGeminiSettings = async () => {
|
|
612
620
|
const wantSettings = await p.confirm({
|
|
613
621
|
message: "Gemini CLI \uC124\uC815 \uD30C\uC77C(.gemini/settings.json)\uC744 \uC124\uCE58\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
|
|
@@ -647,10 +655,33 @@ var installGeminiSettings = (basePath, selectedValues) => {
|
|
|
647
655
|
mkdirSync3(settingsDir, { recursive: true });
|
|
648
656
|
writeFileSync3(settingsPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
649
657
|
};
|
|
658
|
+
var uninstallGeminiSettings = (basePath, selectedValues) => {
|
|
659
|
+
const settingsPath = join7(basePath, ".gemini", "settings.json");
|
|
660
|
+
if (!existsSync3(settingsPath)) return "notFound";
|
|
661
|
+
let existing = {};
|
|
662
|
+
try {
|
|
663
|
+
existing = JSON.parse(readFileSync5(settingsPath, "utf-8"));
|
|
664
|
+
} catch {
|
|
665
|
+
rmSync(settingsPath, { force: true });
|
|
666
|
+
return "deleted";
|
|
667
|
+
}
|
|
668
|
+
let result = existing;
|
|
669
|
+
for (const val of selectedValues) {
|
|
670
|
+
const group = SETTING_GROUPS.find((g) => g.value === val);
|
|
671
|
+
if (!group) continue;
|
|
672
|
+
result = deepRemoveKeys(result, group.patch);
|
|
673
|
+
}
|
|
674
|
+
if (Object.keys(result).length === 0) {
|
|
675
|
+
rmSync(settingsPath, { force: true });
|
|
676
|
+
return "deleted";
|
|
677
|
+
}
|
|
678
|
+
writeFileSync3(settingsPath, JSON.stringify(result, null, 2) + "\n", "utf-8");
|
|
679
|
+
return "cleaned";
|
|
680
|
+
};
|
|
650
681
|
|
|
651
682
|
// src/lib/claude-settings.ts
|
|
652
683
|
import * as p2 from "@clack/prompts";
|
|
653
|
-
import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
684
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync6, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "fs";
|
|
654
685
|
import { join as join8 } from "path";
|
|
655
686
|
var SETTING_GROUPS2 = [
|
|
656
687
|
{
|
|
@@ -666,17 +697,6 @@ var SETTING_GROUPS2 = [
|
|
|
666
697
|
patch: { plansDirectory: "./.claude/plans" }
|
|
667
698
|
}
|
|
668
699
|
];
|
|
669
|
-
var deepMerge2 = (base, patch) => {
|
|
670
|
-
const result = { ...base };
|
|
671
|
-
for (const [key, value] of Object.entries(patch)) {
|
|
672
|
-
if (value !== null && typeof value === "object" && !Array.isArray(value) && typeof result[key] === "object" && result[key] !== null) {
|
|
673
|
-
result[key] = deepMerge2(result[key], value);
|
|
674
|
-
} else {
|
|
675
|
-
result[key] = value;
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
return result;
|
|
679
|
-
};
|
|
680
700
|
var promptClaudeSettings = async () => {
|
|
681
701
|
const wantSettings = await p2.confirm({
|
|
682
702
|
message: "Claude Code \uC124\uC815 \uD30C\uC77C(.claude/settings.local.json)\uC744 \uC124\uCE58\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
|
|
@@ -711,11 +731,131 @@ var installClaudeSettings = (basePath, selectedValues) => {
|
|
|
711
731
|
for (const val of selectedValues) {
|
|
712
732
|
const group = SETTING_GROUPS2.find((g) => g.value === val);
|
|
713
733
|
if (!group) continue;
|
|
714
|
-
merged =
|
|
734
|
+
merged = deepMerge(merged, group.patch);
|
|
715
735
|
}
|
|
716
736
|
mkdirSync4(settingsDir, { recursive: true });
|
|
717
737
|
writeFileSync4(settingsPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
718
738
|
};
|
|
739
|
+
var uninstallClaudeSettings = (basePath, selectedValues) => {
|
|
740
|
+
const settingsPath = join8(basePath, ".claude", "settings.local.json");
|
|
741
|
+
if (!existsSync4(settingsPath)) return "notFound";
|
|
742
|
+
let existing = {};
|
|
743
|
+
try {
|
|
744
|
+
existing = JSON.parse(readFileSync6(settingsPath, "utf-8"));
|
|
745
|
+
} catch {
|
|
746
|
+
rmSync2(settingsPath, { force: true });
|
|
747
|
+
return "deleted";
|
|
748
|
+
}
|
|
749
|
+
let result = existing;
|
|
750
|
+
for (const val of selectedValues) {
|
|
751
|
+
const group = SETTING_GROUPS2.find((g) => g.value === val);
|
|
752
|
+
if (!group) continue;
|
|
753
|
+
result = deepRemoveKeys(result, group.patch);
|
|
754
|
+
}
|
|
755
|
+
if (Object.keys(result).length === 0) {
|
|
756
|
+
rmSync2(settingsPath, { force: true });
|
|
757
|
+
return "deleted";
|
|
758
|
+
}
|
|
759
|
+
writeFileSync4(settingsPath, JSON.stringify(result, null, 2) + "\n", "utf-8");
|
|
760
|
+
return "cleaned";
|
|
761
|
+
};
|
|
762
|
+
|
|
763
|
+
// src/lib/prettier-ignore.ts
|
|
764
|
+
import * as p3 from "@clack/prompts";
|
|
765
|
+
import { existsSync as existsSync5, readFileSync as readFileSync7, rmSync as rmSync3, writeFileSync as writeFileSync5 } from "fs";
|
|
766
|
+
import { join as join9 } from "path";
|
|
767
|
+
var PRETTIER_IGNORE_CONTENT = `# CLAUDE
|
|
768
|
+
.claude/rules/
|
|
769
|
+
**/CLAUDE.md
|
|
770
|
+
|
|
771
|
+
# GEMINI
|
|
772
|
+
**/GEMINI.md
|
|
773
|
+
|
|
774
|
+
# CODEX
|
|
775
|
+
**/AGENTS.md
|
|
776
|
+
**/AGENTS.override.md
|
|
777
|
+
|
|
778
|
+
.ai-ops-manifest.json`;
|
|
779
|
+
var SECTION_START2 = "# ai-ops:start";
|
|
780
|
+
var SECTION_END2 = "# ai-ops:end";
|
|
781
|
+
var wrapSection = (content) => `${SECTION_START2}
|
|
782
|
+
${content}
|
|
783
|
+
${SECTION_END2}`;
|
|
784
|
+
var hasAiOpsSection2 = (content) => content.includes(SECTION_START2) && content.includes(SECTION_END2);
|
|
785
|
+
var replaceSection = (content, newContent) => {
|
|
786
|
+
const lines = content.split("\n");
|
|
787
|
+
const result = [];
|
|
788
|
+
let inside = false;
|
|
789
|
+
let replaced = false;
|
|
790
|
+
for (const line of lines) {
|
|
791
|
+
if (line.trim() === SECTION_START2) {
|
|
792
|
+
inside = true;
|
|
793
|
+
result.push(wrapSection(newContent));
|
|
794
|
+
replaced = true;
|
|
795
|
+
continue;
|
|
796
|
+
}
|
|
797
|
+
if (line.trim() === SECTION_END2) {
|
|
798
|
+
inside = false;
|
|
799
|
+
continue;
|
|
800
|
+
}
|
|
801
|
+
if (!inside) result.push(line);
|
|
802
|
+
}
|
|
803
|
+
if (!replaced) result.push(wrapSection(newContent));
|
|
804
|
+
return result.join("\n");
|
|
805
|
+
};
|
|
806
|
+
var stripAiOpsSection2 = (content) => {
|
|
807
|
+
const lines = content.split("\n");
|
|
808
|
+
const result = [];
|
|
809
|
+
let inside = false;
|
|
810
|
+
for (const line of lines) {
|
|
811
|
+
if (line.trim() === SECTION_START2) {
|
|
812
|
+
inside = true;
|
|
813
|
+
continue;
|
|
814
|
+
}
|
|
815
|
+
if (line.trim() === SECTION_END2) {
|
|
816
|
+
inside = false;
|
|
817
|
+
continue;
|
|
818
|
+
}
|
|
819
|
+
if (!inside) result.push(line);
|
|
820
|
+
}
|
|
821
|
+
return result.join("\n");
|
|
822
|
+
};
|
|
823
|
+
var promptPrettierIgnore = async () => {
|
|
824
|
+
const want = await p3.confirm({
|
|
825
|
+
message: ".prettierignore\uB97C \uC124\uCE58\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C? (VSCode Prettier \uC790\uB3D9 \uD3EC\uB9F7\uC73C\uB85C\uBD80\uD130 AI \uADDC\uCE59 \uD30C\uC77C \uBCF4\uD638)",
|
|
826
|
+
initialValue: false
|
|
827
|
+
});
|
|
828
|
+
if (p3.isCancel(want)) return false;
|
|
829
|
+
return want;
|
|
830
|
+
};
|
|
831
|
+
var installPrettierIgnore = (basePath) => {
|
|
832
|
+
const filePath = join9(basePath, ".prettierignore");
|
|
833
|
+
const section = wrapSection(PRETTIER_IGNORE_CONTENT);
|
|
834
|
+
if (!existsSync5(filePath)) {
|
|
835
|
+
writeFileSync5(filePath, section + "\n", "utf-8");
|
|
836
|
+
return;
|
|
837
|
+
}
|
|
838
|
+
const existing = readFileSync7(filePath, "utf-8");
|
|
839
|
+
if (hasAiOpsSection2(existing)) {
|
|
840
|
+
writeFileSync5(filePath, replaceSection(existing, PRETTIER_IGNORE_CONTENT), "utf-8");
|
|
841
|
+
return;
|
|
842
|
+
}
|
|
843
|
+
const separator = existing.endsWith("\n") ? "\n" : "\n\n";
|
|
844
|
+
writeFileSync5(filePath, existing + separator + section + "\n", "utf-8");
|
|
845
|
+
};
|
|
846
|
+
var uninstallPrettierIgnore = (basePath) => {
|
|
847
|
+
const filePath = join9(basePath, ".prettierignore");
|
|
848
|
+
if (!existsSync5(filePath)) return "notFound";
|
|
849
|
+
const existing = readFileSync7(filePath, "utf-8");
|
|
850
|
+
if (!hasAiOpsSection2(existing)) return "notFound";
|
|
851
|
+
const stripped = stripAiOpsSection2(existing).trim();
|
|
852
|
+
if (stripped.length === 0) {
|
|
853
|
+
rmSync3(filePath, { force: true });
|
|
854
|
+
return "deleted";
|
|
855
|
+
}
|
|
856
|
+
writeFileSync5(filePath, stripped + "\n", "utf-8");
|
|
857
|
+
return "cleaned";
|
|
858
|
+
};
|
|
719
859
|
|
|
720
860
|
// src/commands/init.ts
|
|
721
861
|
var TOOL_OPTIONS = [
|
|
@@ -732,7 +872,7 @@ var deduplicateRules = (rules) => {
|
|
|
732
872
|
});
|
|
733
873
|
};
|
|
734
874
|
var selectPresetAndFineTune = async (workspaceName, presets, allRules) => {
|
|
735
|
-
const preset = await
|
|
875
|
+
const preset = await p4.select({
|
|
736
876
|
message: `[${workspaceName}] \uD504\uB9AC\uC14B\uC744 \uC120\uD0DD\uD558\uC138\uC694`,
|
|
737
877
|
options: presets.map((pr) => ({
|
|
738
878
|
value: pr,
|
|
@@ -740,25 +880,25 @@ var selectPresetAndFineTune = async (workspaceName, presets, allRules) => {
|
|
|
740
880
|
hint: pr.description
|
|
741
881
|
}))
|
|
742
882
|
});
|
|
743
|
-
if (
|
|
883
|
+
if (p4.isCancel(preset)) return null;
|
|
744
884
|
const presetRuleGroups = resolvePresetRuleGroups(preset, allRules);
|
|
745
885
|
const globalGroups = presetRuleGroups.filter((group) => group.rules.every(isGlobalRule));
|
|
746
886
|
const domainGroups = presetRuleGroups.filter((group) => !group.rules.every(isGlobalRule));
|
|
747
887
|
const globalGroupIds = globalGroups.map((group) => group.id);
|
|
748
888
|
const globalRules = globalGroupIds.length > 0 ? resolvePresetRules({ ...preset, rules: globalGroupIds }, allRules) : [];
|
|
749
889
|
if (globalRules.length > 0) {
|
|
750
|
-
|
|
890
|
+
p4.note(globalRules.map((r) => ` \u2713 ${r.id}`).join("\n"), `[${workspaceName}] \uAE30\uBCF8 \uADDC\uCE59 (\uC7A0\uAE08)`);
|
|
751
891
|
}
|
|
752
892
|
if (domainGroups.length === 0) {
|
|
753
893
|
return { workspace: workspaceName, preset, finalRules: resolvePresetRules(preset, allRules) };
|
|
754
894
|
}
|
|
755
|
-
const selectedDomain = await
|
|
895
|
+
const selectedDomain = await p4.multiselect({
|
|
756
896
|
message: `[${workspaceName}] \uB3C4\uBA54\uC778 \uADDC\uCE59 \uC120\uD0DD (\uD574\uC81C\uD558\uC5EC \uC81C\uC678)`,
|
|
757
897
|
options: domainGroups.map((group) => ({ value: group.id, label: group.id })),
|
|
758
898
|
initialValues: domainGroups.map((group) => group.id),
|
|
759
899
|
required: false
|
|
760
900
|
});
|
|
761
|
-
if (
|
|
901
|
+
if (p4.isCancel(selectedDomain)) return null;
|
|
762
902
|
const selectedLogicalRuleIds = [...globalGroupIds, ...selectedDomain];
|
|
763
903
|
return {
|
|
764
904
|
workspace: workspaceName,
|
|
@@ -774,8 +914,8 @@ var installHierarchicalMonorepo = (toolId, mappings, basePath, meta) => {
|
|
|
774
914
|
const { global } = partitionRules(allRules);
|
|
775
915
|
if (global.length > 0) {
|
|
776
916
|
const rootAction = {
|
|
777
|
-
relativePath:
|
|
778
|
-
content:
|
|
917
|
+
relativePath: join10(config.dir, config.rootFileName),
|
|
918
|
+
content: wrapWithSection(renderRulesToMarkdown(global), meta)
|
|
779
919
|
};
|
|
780
920
|
const r = installFiles(basePath, [rootAction], meta);
|
|
781
921
|
written.push(...r.written);
|
|
@@ -785,8 +925,8 @@ var installHierarchicalMonorepo = (toolId, mappings, basePath, meta) => {
|
|
|
785
925
|
const { domain } = partitionRules(mapping.finalRules);
|
|
786
926
|
if (domain.length === 0) continue;
|
|
787
927
|
const domainAction = {
|
|
788
|
-
relativePath:
|
|
789
|
-
content:
|
|
928
|
+
relativePath: join10(mapping.workspace, config.domainFileName),
|
|
929
|
+
content: wrapWithSection(renderRulesToMarkdown(domain), meta)
|
|
790
930
|
};
|
|
791
931
|
const r = installFiles(basePath, [domainAction], meta);
|
|
792
932
|
written.push(...r.written);
|
|
@@ -808,22 +948,22 @@ var installClaudeCodeMonorepo = (mappings, basePath, meta) => {
|
|
|
808
948
|
var initCommand = async () => {
|
|
809
949
|
const basePath = resolveBasePath();
|
|
810
950
|
const rulesDir = resolveRulesDir();
|
|
811
|
-
|
|
812
|
-
const selectedTools = await
|
|
951
|
+
p4.intro("ai-ops init");
|
|
952
|
+
const selectedTools = await p4.multiselect({
|
|
813
953
|
message: "AI \uB3C4\uAD6C\uB97C \uC120\uD0DD\uD558\uC138\uC694",
|
|
814
954
|
options: TOOL_OPTIONS,
|
|
815
955
|
required: true
|
|
816
956
|
});
|
|
817
|
-
if (
|
|
818
|
-
|
|
957
|
+
if (p4.isCancel(selectedTools)) {
|
|
958
|
+
p4.cancel("\uCDE8\uC18C\uB428");
|
|
819
959
|
process.exit(0);
|
|
820
960
|
}
|
|
821
|
-
const isMonorepo = await
|
|
961
|
+
const isMonorepo = await p4.confirm({
|
|
822
962
|
message: "\uBAA8\uB178\uB808\uD3EC \uD504\uB85C\uC81D\uD2B8\uC785\uB2C8\uAE4C?",
|
|
823
963
|
initialValue: false
|
|
824
964
|
});
|
|
825
|
-
if (
|
|
826
|
-
|
|
965
|
+
if (p4.isCancel(isMonorepo)) {
|
|
966
|
+
p4.cancel("\uCDE8\uC18C\uB428");
|
|
827
967
|
process.exit(0);
|
|
828
968
|
}
|
|
829
969
|
const allRules = loadAllRules(rulesDir);
|
|
@@ -833,25 +973,25 @@ var initCommand = async () => {
|
|
|
833
973
|
if (!isMonorepo) {
|
|
834
974
|
const mapping = await selectPresetAndFineTune(".", presets, allRules);
|
|
835
975
|
if (!mapping) {
|
|
836
|
-
|
|
976
|
+
p4.cancel("\uCDE8\uC18C\uB428");
|
|
837
977
|
process.exit(0);
|
|
838
978
|
}
|
|
839
979
|
mappings.push(mapping);
|
|
840
980
|
} else {
|
|
841
981
|
const candidates = listWorkspaceCandidates(basePath);
|
|
842
|
-
const selectedWorkspaces = await
|
|
982
|
+
const selectedWorkspaces = await p4.multiselect({
|
|
843
983
|
message: "\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4\uB97C \uC120\uD0DD\uD558\uC138\uC694",
|
|
844
984
|
options: candidates.map((c) => ({ value: c, label: c })),
|
|
845
985
|
required: true
|
|
846
986
|
});
|
|
847
|
-
if (
|
|
848
|
-
|
|
987
|
+
if (p4.isCancel(selectedWorkspaces)) {
|
|
988
|
+
p4.cancel("\uCDE8\uC18C\uB428");
|
|
849
989
|
process.exit(0);
|
|
850
990
|
}
|
|
851
991
|
for (const ws of selectedWorkspaces) {
|
|
852
992
|
const mapping = await selectPresetAndFineTune(ws, presets, allRules);
|
|
853
993
|
if (!mapping) {
|
|
854
|
-
|
|
994
|
+
p4.cancel("\uCDE8\uC18C\uB428");
|
|
855
995
|
process.exit(0);
|
|
856
996
|
}
|
|
857
997
|
mappings.push(mapping);
|
|
@@ -859,7 +999,8 @@ var initCommand = async () => {
|
|
|
859
999
|
}
|
|
860
1000
|
const geminiSettingValues = selectedTools.includes("gemini") ? await promptGeminiSettings() : null;
|
|
861
1001
|
const claudeSettingValues = selectedTools.includes("claude-code") ? await promptClaudeSettings() : null;
|
|
862
|
-
const
|
|
1002
|
+
const wantPrettierIgnore = await promptPrettierIgnore();
|
|
1003
|
+
const s = p4.spinner();
|
|
863
1004
|
s.start("\uADDC\uCE59 \uC124\uCE58 \uC911...");
|
|
864
1005
|
const meta = { sourceHash, generatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
865
1006
|
const allInstalledFiles = [];
|
|
@@ -885,11 +1026,12 @@ var initCommand = async () => {
|
|
|
885
1026
|
}
|
|
886
1027
|
if (geminiSettingValues && geminiSettingValues.length > 0) {
|
|
887
1028
|
installGeminiSettings(basePath, geminiSettingValues);
|
|
888
|
-
allInstalledFiles.push(".gemini/settings.json");
|
|
889
1029
|
}
|
|
890
1030
|
if (claudeSettingValues && claudeSettingValues.length > 0) {
|
|
891
1031
|
installClaudeSettings(basePath, claudeSettingValues);
|
|
892
|
-
|
|
1032
|
+
}
|
|
1033
|
+
if (wantPrettierIgnore) {
|
|
1034
|
+
installPrettierIgnore(basePath);
|
|
893
1035
|
}
|
|
894
1036
|
s.stop("\uADDC\uCE59 \uC124\uCE58 \uC644\uB8CC");
|
|
895
1037
|
const allInstalledRuleIds = deduplicateRules(mappings.flatMap((m) => m.finalRules)).map((r) => r.id);
|
|
@@ -904,32 +1046,33 @@ var initCommand = async () => {
|
|
|
904
1046
|
installedRules: allInstalledRuleIds,
|
|
905
1047
|
installedFiles: allInstalledFiles,
|
|
906
1048
|
appendedFiles: allAppended,
|
|
907
|
-
settings: claudeSettingValues || geminiSettingValues ? {
|
|
1049
|
+
settings: claudeSettingValues || geminiSettingValues || wantPrettierIgnore ? {
|
|
908
1050
|
claude: claudeSettingValues ? [...claudeSettingValues] : void 0,
|
|
909
|
-
gemini: geminiSettingValues ? [...geminiSettingValues] : void 0
|
|
1051
|
+
gemini: geminiSettingValues ? [...geminiSettingValues] : void 0,
|
|
1052
|
+
prettierignore: wantPrettierIgnore || void 0
|
|
910
1053
|
} : void 0,
|
|
911
1054
|
cliVersion: getCliVersion(),
|
|
912
1055
|
sourceHash
|
|
913
1056
|
});
|
|
914
1057
|
writeManifest(resolveManifestPath(basePath), manifest);
|
|
915
1058
|
if (allAppended.length > 0) {
|
|
916
|
-
|
|
1059
|
+
p4.log.info(`\uAE30\uC874 \uD30C\uC77C\uC5D0 \uC139\uC158 \uCD94\uAC00\uB428 (\uB0B4\uC6A9 \uBCF4\uC874):
|
|
917
1060
|
${allAppended.map((f) => ` ${f}`).join("\n")}`);
|
|
918
1061
|
}
|
|
919
|
-
|
|
920
|
-
|
|
1062
|
+
p4.log.success(`\uC124\uCE58\uB41C \uADDC\uCE59: ${allInstalledRuleIds.length}\uAC1C`);
|
|
1063
|
+
p4.outro("ai-ops init \uC644\uB8CC");
|
|
921
1064
|
};
|
|
922
1065
|
|
|
923
1066
|
// src/commands/update.ts
|
|
924
|
-
import * as
|
|
925
|
-
import { join as
|
|
1067
|
+
import * as p5 from "@clack/prompts";
|
|
1068
|
+
import { join as join11 } from "path";
|
|
926
1069
|
var updateCommand = async (opts) => {
|
|
927
1070
|
const basePath = resolveBasePath();
|
|
928
1071
|
const manifestPath = resolveManifestPath(basePath);
|
|
929
|
-
|
|
1072
|
+
p5.intro("ai-ops update");
|
|
930
1073
|
const manifest = readManifest(manifestPath);
|
|
931
1074
|
if (!manifest) {
|
|
932
|
-
|
|
1075
|
+
p5.log.error("manifest\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. \uBA3C\uC800 ai-ops init\uC744 \uC2E4\uD589\uD558\uC138\uC694.");
|
|
933
1076
|
process.exit(1);
|
|
934
1077
|
}
|
|
935
1078
|
const rulesDir = resolveRulesDir();
|
|
@@ -942,11 +1085,11 @@ var updateCommand = async (opts) => {
|
|
|
942
1085
|
currentCliVersion: cliVersion
|
|
943
1086
|
});
|
|
944
1087
|
if (diffResult.status === "up-to-date" && !opts.force) {
|
|
945
|
-
|
|
946
|
-
|
|
1088
|
+
p5.log.info("\uBCC0\uACBD \uC0AC\uD56D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
1089
|
+
p5.outro("ai-ops update \uC644\uB8CC");
|
|
947
1090
|
return;
|
|
948
1091
|
}
|
|
949
|
-
const s =
|
|
1092
|
+
const s = p5.spinner();
|
|
950
1093
|
s.start("\uADDC\uCE59 \uAC31\uC2E0 \uC911...");
|
|
951
1094
|
const allRules = loadAllRules(rulesDir);
|
|
952
1095
|
const meta = { sourceHash, generatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
@@ -975,8 +1118,8 @@ var updateCommand = async (opts) => {
|
|
|
975
1118
|
const { global } = partitionRules(allRulesToInstall);
|
|
976
1119
|
if (global.length > 0) {
|
|
977
1120
|
const rootAction = {
|
|
978
|
-
relativePath:
|
|
979
|
-
content:
|
|
1121
|
+
relativePath: join11(config.dir, config.rootFileName),
|
|
1122
|
+
content: wrapWithSection(renderRulesToMarkdown(global), meta)
|
|
980
1123
|
};
|
|
981
1124
|
const r = installFiles(basePath, [rootAction], meta);
|
|
982
1125
|
allInstalledFiles.push(...r.written);
|
|
@@ -988,8 +1131,8 @@ var updateCommand = async (opts) => {
|
|
|
988
1131
|
const { domain } = partitionRules(wsRules);
|
|
989
1132
|
if (domain.length === 0) continue;
|
|
990
1133
|
const domainAction = {
|
|
991
|
-
relativePath:
|
|
992
|
-
content:
|
|
1134
|
+
relativePath: join11(ws, config.domainFileName),
|
|
1135
|
+
content: wrapWithSection(renderRulesToMarkdown(domain), meta)
|
|
993
1136
|
};
|
|
994
1137
|
const r = installFiles(basePath, [domainAction], meta);
|
|
995
1138
|
allInstalledFiles.push(...r.written);
|
|
@@ -1015,6 +1158,9 @@ var updateCommand = async (opts) => {
|
|
|
1015
1158
|
if (manifest.settings?.gemini) {
|
|
1016
1159
|
installGeminiSettings(basePath, manifest.settings.gemini);
|
|
1017
1160
|
}
|
|
1161
|
+
if (manifest.settings?.prettierignore) {
|
|
1162
|
+
installPrettierIgnore(basePath);
|
|
1163
|
+
}
|
|
1018
1164
|
const newManifest = buildManifest({
|
|
1019
1165
|
tools: manifest.tools,
|
|
1020
1166
|
scope: manifest.scope,
|
|
@@ -1025,24 +1171,25 @@ var updateCommand = async (opts) => {
|
|
|
1025
1171
|
appendedFiles: allAppended.length > 0 ? allAppended : manifest.appended_files,
|
|
1026
1172
|
settings: manifest.settings ? {
|
|
1027
1173
|
claude: manifest.settings.claude,
|
|
1028
|
-
gemini: manifest.settings.gemini
|
|
1174
|
+
gemini: manifest.settings.gemini,
|
|
1175
|
+
prettierignore: manifest.settings.prettierignore
|
|
1029
1176
|
} : void 0,
|
|
1030
1177
|
cliVersion,
|
|
1031
1178
|
sourceHash
|
|
1032
1179
|
});
|
|
1033
1180
|
writeManifest(manifestPath, newManifest);
|
|
1034
1181
|
s.stop("\uADDC\uCE59 \uAC31\uC2E0 \uC644\uB8CC");
|
|
1035
|
-
|
|
1182
|
+
p5.outro("ai-ops update \uC644\uB8CC");
|
|
1036
1183
|
};
|
|
1037
1184
|
|
|
1038
1185
|
// src/commands/diff.ts
|
|
1039
|
-
import * as
|
|
1186
|
+
import * as p6 from "@clack/prompts";
|
|
1040
1187
|
var diffCommand = async () => {
|
|
1041
1188
|
const basePath = resolveBasePath();
|
|
1042
|
-
|
|
1189
|
+
p6.intro("ai-ops diff");
|
|
1043
1190
|
const manifest = readManifest(resolveManifestPath(basePath));
|
|
1044
1191
|
if (!manifest) {
|
|
1045
|
-
|
|
1192
|
+
p6.log.error("manifest\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. \uBA3C\uC800 ai-ops init\uC744 \uC2E4\uD589\uD558\uC138\uC694.");
|
|
1046
1193
|
process.exit(1);
|
|
1047
1194
|
}
|
|
1048
1195
|
const sourceHash = computeSourceHash(resolveRulesDir());
|
|
@@ -1052,27 +1199,27 @@ var diffCommand = async () => {
|
|
|
1052
1199
|
currentSourceHash: sourceHash
|
|
1053
1200
|
});
|
|
1054
1201
|
if (result.status === "up-to-date") {
|
|
1055
|
-
|
|
1202
|
+
p6.log.success("\uBCC0\uACBD \uC0AC\uD56D \uC5C6\uC74C. \uCD5C\uC2E0 \uC0C1\uD0DC\uC785\uB2C8\uB2E4.");
|
|
1056
1203
|
} else {
|
|
1057
1204
|
if (result.sourceChanged) {
|
|
1058
|
-
|
|
1205
|
+
p6.log.warn(`\uC18C\uC2A4 \uBCC0\uACBD \uAC10\uC9C0: ${manifest.sourceHash} \u2192 ${sourceHash}`);
|
|
1059
1206
|
}
|
|
1060
1207
|
if (result.added.length > 0) {
|
|
1061
|
-
|
|
1208
|
+
p6.log.info(`\uCD94\uAC00\uB41C \uADDC\uCE59: ${result.added.join(", ")}`);
|
|
1062
1209
|
}
|
|
1063
1210
|
if (result.removed.length > 0) {
|
|
1064
|
-
|
|
1211
|
+
p6.log.info(`\uC81C\uAC70\uB41C \uADDC\uCE59: ${result.removed.join(", ")}`);
|
|
1065
1212
|
}
|
|
1066
1213
|
}
|
|
1067
|
-
|
|
1214
|
+
p6.outro("ai-ops diff \uC644\uB8CC");
|
|
1068
1215
|
};
|
|
1069
1216
|
|
|
1070
1217
|
// src/commands/uninstall.ts
|
|
1071
|
-
import * as
|
|
1072
|
-
import { rmSync as
|
|
1218
|
+
import * as p7 from "@clack/prompts";
|
|
1219
|
+
import { rmSync as rmSync5 } from "fs";
|
|
1073
1220
|
|
|
1074
1221
|
// src/lib/uninstall.ts
|
|
1075
|
-
import { existsSync as
|
|
1222
|
+
import { existsSync as existsSync6, readFileSync as readFileSync8, rmSync as rmSync4, readdirSync as readdirSync4, writeFileSync as writeFileSync6 } from "fs";
|
|
1076
1223
|
import { resolve as resolve6, dirname as dirname5 } from "path";
|
|
1077
1224
|
var removeFiles = (basePath, relativePaths) => {
|
|
1078
1225
|
const deleted = [];
|
|
@@ -1081,23 +1228,26 @@ var removeFiles = (basePath, relativePaths) => {
|
|
|
1081
1228
|
const notFound = [];
|
|
1082
1229
|
for (const rel of relativePaths) {
|
|
1083
1230
|
const absPath = resolve6(basePath, rel);
|
|
1084
|
-
if (!
|
|
1231
|
+
if (!existsSync6(absPath)) {
|
|
1085
1232
|
notFound.push(rel);
|
|
1086
1233
|
continue;
|
|
1087
1234
|
}
|
|
1088
|
-
const content =
|
|
1089
|
-
if (
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1235
|
+
const content = readFileSync8(absPath, "utf-8");
|
|
1236
|
+
if (hasAiOpsSection(content)) {
|
|
1237
|
+
const stripped = stripAiOpsSection(content);
|
|
1238
|
+
if (stripped.trim().length === 0) {
|
|
1239
|
+
rmSync4(absPath);
|
|
1240
|
+
deleted.push(rel);
|
|
1094
1241
|
} else {
|
|
1095
|
-
|
|
1242
|
+
writeFileSync6(absPath, stripped, "utf-8");
|
|
1243
|
+
cleaned.push(rel);
|
|
1096
1244
|
}
|
|
1097
|
-
|
|
1245
|
+
} else if (hasLegacyHeader(content)) {
|
|
1246
|
+
rmSync4(absPath);
|
|
1247
|
+
deleted.push(rel);
|
|
1248
|
+
} else {
|
|
1249
|
+
skipped.push(rel);
|
|
1098
1250
|
}
|
|
1099
|
-
rmSync(absPath);
|
|
1100
|
-
deleted.push(rel);
|
|
1101
1251
|
}
|
|
1102
1252
|
return { deleted, cleaned, skipped, notFound };
|
|
1103
1253
|
};
|
|
@@ -1105,11 +1255,11 @@ var cleanEmptyDirs = (basePath, dirs) => {
|
|
|
1105
1255
|
const removed = [];
|
|
1106
1256
|
for (const dir of dirs) {
|
|
1107
1257
|
const absDir = resolve6(basePath, dir);
|
|
1108
|
-
if (!
|
|
1258
|
+
if (!existsSync6(absDir)) continue;
|
|
1109
1259
|
try {
|
|
1110
1260
|
const entries = readdirSync4(absDir);
|
|
1111
1261
|
if (entries.length === 0) {
|
|
1112
|
-
|
|
1262
|
+
rmSync4(absDir, { recursive: true });
|
|
1113
1263
|
removed.push(dir);
|
|
1114
1264
|
}
|
|
1115
1265
|
} catch {
|
|
@@ -1129,64 +1279,85 @@ var collectManagedDirs = (relativePaths) => {
|
|
|
1129
1279
|
};
|
|
1130
1280
|
|
|
1131
1281
|
// src/commands/uninstall.ts
|
|
1282
|
+
var SETTINGS_PATHS = /* @__PURE__ */ new Set([".claude/settings.local.json", ".gemini/settings.json"]);
|
|
1132
1283
|
var uninstallCommand = async () => {
|
|
1133
1284
|
const basePath = resolveBasePath();
|
|
1134
1285
|
const manifestPath = resolveManifestPath(basePath);
|
|
1135
|
-
|
|
1286
|
+
p7.intro("ai-ops uninstall");
|
|
1136
1287
|
const manifest = readManifest(manifestPath);
|
|
1137
1288
|
if (!manifest) {
|
|
1138
|
-
|
|
1289
|
+
p7.log.error("manifest\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. \uBA3C\uC800 ai-ops init\uC744 \uC2E4\uD589\uD558\uC138\uC694.");
|
|
1139
1290
|
process.exit(1);
|
|
1140
1291
|
}
|
|
1141
1292
|
const targetFiles = [
|
|
1142
1293
|
...manifest.installed_files ?? inferInstalledFiles(manifest),
|
|
1143
1294
|
...manifest.appended_files ?? []
|
|
1144
|
-
];
|
|
1295
|
+
].filter((f) => !SETTINGS_PATHS.has(f));
|
|
1145
1296
|
if (targetFiles.length === 0) {
|
|
1146
|
-
|
|
1147
|
-
|
|
1297
|
+
p7.log.warn("\uC0AD\uC81C\uD560 \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
1298
|
+
p7.outro("ai-ops uninstall \uC644\uB8CC");
|
|
1148
1299
|
return;
|
|
1149
1300
|
}
|
|
1150
|
-
|
|
1301
|
+
p7.log.info(`\uC0AD\uC81C \uB300\uC0C1 \uD30C\uC77C (${targetFiles.length}\uAC1C):
|
|
1151
1302
|
${targetFiles.map((f) => ` ${f}`).join("\n")}`);
|
|
1152
|
-
const confirmed = await
|
|
1303
|
+
const confirmed = await p7.confirm({
|
|
1153
1304
|
message: "\uC704 \uD30C\uC77C\uACFC manifest\uB97C \uBAA8\uB450 \uC0AD\uC81C\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
|
|
1154
1305
|
initialValue: false
|
|
1155
1306
|
});
|
|
1156
|
-
if (
|
|
1157
|
-
|
|
1307
|
+
if (p7.isCancel(confirmed) || !confirmed) {
|
|
1308
|
+
p7.cancel("\uCDE8\uC18C\uB428");
|
|
1158
1309
|
process.exit(0);
|
|
1159
1310
|
}
|
|
1311
|
+
const settingsMessages = [];
|
|
1312
|
+
if (manifest.settings?.claude) {
|
|
1313
|
+
const status = uninstallClaudeSettings(basePath, manifest.settings.claude);
|
|
1314
|
+
if (status === "deleted") settingsMessages.push("\uC0AD\uC81C: .claude/settings.local.json");
|
|
1315
|
+
else if (status === "cleaned") settingsMessages.push("ai-ops \uD0A4 \uC81C\uAC70 (\uC0AC\uC6A9\uC790 \uC124\uC815 \uBCF4\uC874): .claude/settings.local.json");
|
|
1316
|
+
}
|
|
1317
|
+
if (manifest.settings?.gemini) {
|
|
1318
|
+
const status = uninstallGeminiSettings(basePath, manifest.settings.gemini);
|
|
1319
|
+
if (status === "deleted") settingsMessages.push("\uC0AD\uC81C: .gemini/settings.json");
|
|
1320
|
+
else if (status === "cleaned") settingsMessages.push("ai-ops \uD0A4 \uC81C\uAC70 (\uC0AC\uC6A9\uC790 \uC124\uC815 \uBCF4\uC874): .gemini/settings.json");
|
|
1321
|
+
}
|
|
1322
|
+
if (manifest.settings?.prettierignore) {
|
|
1323
|
+
const status = uninstallPrettierIgnore(basePath);
|
|
1324
|
+
if (status === "deleted") settingsMessages.push("\uC0AD\uC81C: .prettierignore");
|
|
1325
|
+
else if (status === "cleaned") settingsMessages.push("ai-ops \uC139\uC158 \uC81C\uAC70 (\uC0AC\uC6A9\uC790 \uB0B4\uC6A9 \uBCF4\uC874): .prettierignore");
|
|
1326
|
+
}
|
|
1160
1327
|
const result = removeFiles(basePath, targetFiles);
|
|
1161
1328
|
const dirs = collectManagedDirs(targetFiles);
|
|
1162
1329
|
const removedDirs = cleanEmptyDirs(basePath, dirs);
|
|
1163
|
-
|
|
1330
|
+
rmSync5(manifestPath, { force: true });
|
|
1164
1331
|
if (result.deleted.length > 0) {
|
|
1165
|
-
|
|
1332
|
+
p7.log.success(`\uC0AD\uC81C \uC644\uB8CC (${result.deleted.length}\uAC1C):
|
|
1166
1333
|
${result.deleted.map((f) => ` ${f}`).join("\n")}`);
|
|
1167
1334
|
}
|
|
1168
1335
|
if (result.cleaned.length > 0) {
|
|
1169
|
-
|
|
1336
|
+
p7.log.success(
|
|
1170
1337
|
`\uC139\uC158 \uC81C\uAC70 \uC644\uB8CC (\uC0AC\uC6A9\uC790 \uB0B4\uC6A9 \uBCF4\uC874, ${result.cleaned.length}\uAC1C):
|
|
1171
1338
|
${result.cleaned.map((f) => ` ${f}`).join("\n")}`
|
|
1172
1339
|
);
|
|
1173
1340
|
}
|
|
1174
1341
|
if (result.skipped.length > 0) {
|
|
1175
|
-
|
|
1342
|
+
p7.log.warn(
|
|
1176
1343
|
`\uAC74\uB108\uB700 (non-managed \uD30C\uC77C \uBCF4\uD638, ${result.skipped.length}\uAC1C):
|
|
1177
1344
|
${result.skipped.map((f) => ` ${f}`).join("\n")}`
|
|
1178
1345
|
);
|
|
1179
1346
|
}
|
|
1180
1347
|
if (result.notFound.length > 0) {
|
|
1181
|
-
|
|
1348
|
+
p7.log.info(`\uC774\uBBF8 \uC5C6\uC74C (${result.notFound.length}\uAC1C):
|
|
1182
1349
|
${result.notFound.map((f) => ` ${f}`).join("\n")}`);
|
|
1183
1350
|
}
|
|
1184
1351
|
if (removedDirs.length > 0) {
|
|
1185
|
-
|
|
1352
|
+
p7.log.info(`\uBE48 \uB514\uB809\uD1A0\uB9AC \uC815\uB9AC (${removedDirs.length}\uAC1C):
|
|
1186
1353
|
${removedDirs.map((d) => ` ${d}`).join("\n")}`);
|
|
1187
1354
|
}
|
|
1188
|
-
|
|
1189
|
-
|
|
1355
|
+
if (settingsMessages.length > 0) {
|
|
1356
|
+
p7.log.success(`\uC124\uC815 \uD30C\uC77C \uCC98\uB9AC:
|
|
1357
|
+
${settingsMessages.map((m) => ` ${m}`).join("\n")}`);
|
|
1358
|
+
}
|
|
1359
|
+
p7.log.success(`manifest \uC0AD\uC81C: ${MANIFEST_FILENAME}`);
|
|
1360
|
+
p7.outro("ai-ops uninstall \uC644\uB8CC");
|
|
1190
1361
|
};
|
|
1191
1362
|
|
|
1192
1363
|
// src/bin/index.ts
|