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