ai-ops-cli 0.2.0 → 0.2.2
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/README.md +23 -0
- package/data/rules/communication.yaml +3 -2
- package/dist/bin/index.js +242 -236
- package/dist/bin/index.js.map +1 -1
- package/package.json +1 -1
package/dist/bin/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { Command } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/commands/init.ts
|
|
7
|
-
import * as
|
|
7
|
+
import * as p3 from "@clack/prompts";
|
|
8
8
|
|
|
9
9
|
// src/core/schemas/rule.schema.ts
|
|
10
10
|
import { z } from "zod";
|
|
@@ -768,7 +768,7 @@ var computeDiff = (params) => {
|
|
|
768
768
|
|
|
769
769
|
// src/core/install-plan.ts
|
|
770
770
|
import { join as join7 } from "path";
|
|
771
|
-
var CODEX_PLAN_BODY = "## 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.";
|
|
771
|
+
var CODEX_PLAN_BODY = "## Plan Snapshot (Plan mode only)\n\n- This rule applies only when Codex is running in `collaboration_mode=Plan`.\n- Before implementation (file edits/creates, installs, commits) and before leaving Plan mode, save the latest plan content to `.codex/plans/YYYYMMDD_<topic>.md`.\n- In `Default` mode, do not automatically create or update plan files.";
|
|
772
772
|
var buildInstallPlan = (params) => {
|
|
773
773
|
const { toolId, renderResult, meta } = params;
|
|
774
774
|
if (toolId === "claude-code" && renderResult.tool === "claude-code") {
|
|
@@ -813,6 +813,43 @@ var buildInstallPlan = (params) => {
|
|
|
813
813
|
return [];
|
|
814
814
|
};
|
|
815
815
|
|
|
816
|
+
// src/data/spec-readme.ts
|
|
817
|
+
var SPEC_README_TEMPLATE = `# Specs
|
|
818
|
+
|
|
819
|
+
\uC774 \uB514\uB809\uD1A0\uB9AC\uB294 AI \uD611\uC5C5 \uAE30\uBC18 spec \uD30C\uC774\uD504\uB77C\uC778\uC744 \uAD00\uB9AC\uD569\uB2C8\uB2E4.
|
|
820
|
+
|
|
821
|
+
## \uB514\uB809\uD1A0\uB9AC \uAD6C\uC870
|
|
822
|
+
|
|
823
|
+
\`\`\`
|
|
824
|
+
specs/
|
|
825
|
+
\u251C\u2500\u2500 baseline/ # \uAE30\uC900 spec \uBB38\uC11C (\uCD08\uAE30 \uC694\uAD6C\uC0AC\uD56D, \uD655\uC815\uB41C \uC2A4\uD399)
|
|
826
|
+
\u2514\u2500\u2500 delta/ # \uBCC0\uACBD spec \uBB38\uC11C (\uAE30\uC900 \uB300\uBE44 \uCD94\uAC00/\uC218\uC815 \uC0AC\uD56D)
|
|
827
|
+
\`\`\`
|
|
828
|
+
|
|
829
|
+
## \uC0AC\uC6A9 \uBC29\uBC95
|
|
830
|
+
|
|
831
|
+
### baseline
|
|
832
|
+
|
|
833
|
+
\uD504\uB85C\uC81D\uD2B8\uC758 \uCD08\uAE30 \uB610\uB294 \uD655\uC815\uB41C \uC2A4\uD399 \uBB38\uC11C\uB97C \`baseline/\` \uB514\uB809\uD1A0\uB9AC\uC5D0 \uC800\uC7A5\uD569\uB2C8\uB2E4.
|
|
834
|
+
|
|
835
|
+
- \uD30C\uC77C\uBA85: \`<feature-name>.md\` (kebab-case)
|
|
836
|
+
- \uB0B4\uC6A9: \uC694\uAD6C\uC0AC\uD56D, \uB3C4\uBA54\uC778 \uC6A9\uC5B4, \uC81C\uC57D \uC870\uAC74 \uB4F1
|
|
837
|
+
|
|
838
|
+
### delta
|
|
839
|
+
|
|
840
|
+
\uAE30\uC900 \uC2A4\uD399 \uB300\uBE44 \uBCC0\uACBD\uB418\uB294 \uB0B4\uC6A9\uC744 \`delta/\` \uB514\uB809\uD1A0\uB9AC\uC5D0 \uC800\uC7A5\uD569\uB2C8\uB2E4.
|
|
841
|
+
|
|
842
|
+
- \uD30C\uC77C\uBA85: \`<YYYYMMDD>-<feature-name>.md\`
|
|
843
|
+
- \uB0B4\uC6A9: \uBCC0\uACBD \uC774\uC720, \uBCC0\uACBD \uC804/\uD6C4 \uBE44\uAD50, \uC601\uD5A5 \uBC94\uC704 \uB4F1
|
|
844
|
+
`;
|
|
845
|
+
|
|
846
|
+
// src/core/spec-plan.ts
|
|
847
|
+
var buildSpecInitPlan = () => [
|
|
848
|
+
{ relativePath: "specs/README.md", content: SPEC_README_TEMPLATE },
|
|
849
|
+
{ relativePath: "specs/baseline/.gitkeep", content: "" },
|
|
850
|
+
{ relativePath: "specs/delta/.gitkeep", content: "" }
|
|
851
|
+
];
|
|
852
|
+
|
|
816
853
|
// src/core/uninstall-plan.ts
|
|
817
854
|
import { join as join8 } from "path";
|
|
818
855
|
var inferInstalledFiles = (manifest) => {
|
|
@@ -973,7 +1010,7 @@ var removeDirectories = (basePath, relativeDirs) => {
|
|
|
973
1010
|
return removed;
|
|
974
1011
|
};
|
|
975
1012
|
|
|
976
|
-
// src/lib/
|
|
1013
|
+
// src/lib/tool-settings.ts
|
|
977
1014
|
import * as p from "@clack/prompts";
|
|
978
1015
|
import { existsSync as existsSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync6, rmSync as rmSync2, writeFileSync as writeFileSync5 } from "fs";
|
|
979
1016
|
import { join as join11 } from "path";
|
|
@@ -1012,57 +1049,24 @@ var deepRemoveKeys = (base, patch) => {
|
|
|
1012
1049
|
var PROMPT_CANCELLED = /* @__PURE__ */ Symbol("prompt-cancelled");
|
|
1013
1050
|
var isPromptCancelled = (value) => value === PROMPT_CANCELLED;
|
|
1014
1051
|
|
|
1015
|
-
// src/lib/
|
|
1016
|
-
var
|
|
1017
|
-
{
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
hint: "ui.showLineNumbers: false \u2014 \uCF54\uB4DC \uBCF5\uC0AC \uC2DC \uC904 \uBC88\uD638\uAC00 \uD3EC\uD568\uB418\uC9C0 \uC54A\uB3C4\uB85D \uBE44\uD65C\uC131\uD654",
|
|
1021
|
-
patch: { ui: { showLineNumbers: false } }
|
|
1022
|
-
},
|
|
1023
|
-
{
|
|
1024
|
-
value: "plan",
|
|
1025
|
-
label: "Plan \u2014 \uACC4\uD68D \uD30C\uC77C \uC800\uC7A5 \uBC0F \uBAA8\uB378 \uB77C\uC6B0\uD305",
|
|
1026
|
-
hint: "general.plan.directory: .gemini/plans, modelRouting: true \u2014 AI \uACC4\uD68D\uC744 \uD30C\uC77C\uB85C \uC800\uC7A5\uD558\uACE0 \uD0DC\uC2A4\uD06C\uBCC4 \uCD5C\uC801 \uBAA8\uB378 \uC790\uB3D9 \uC120\uD0DD",
|
|
1027
|
-
patch: { general: { plan: { directory: ".gemini/plans", modelRouting: true } } }
|
|
1028
|
-
},
|
|
1029
|
-
{
|
|
1030
|
-
value: "sessionRetention",
|
|
1031
|
-
label: "Session Retention \u2014 \uC138\uC158 30\uC77C \uBCF4\uC874",
|
|
1032
|
-
hint: "general.sessionRetention.maxAge: 30d \u2014 \uC774\uC804 \uB300\uD654 \uCEE8\uD14D\uC2A4\uD2B8\uB97C 30\uC77C\uAC04 \uC720\uC9C0",
|
|
1033
|
-
patch: { general: { sessionRetention: { maxAge: "30d" } } }
|
|
1034
|
-
},
|
|
1035
|
-
{
|
|
1036
|
-
value: "experimental",
|
|
1037
|
-
label: "Experimental \u2014 JIT \uCEE8\uD14D\uC2A4\uD2B8 + Plan \uAE30\uB2A5",
|
|
1038
|
-
hint: "experimental.jitContext: true, plan: true \u2014 \uC11C\uBE0C\uB514\uB809\uD1A0\uB9AC \uCEE8\uD14D\uC2A4\uD2B8 \uC9C0\uC5F0 \uB85C\uB529 \uBC0F \uACC4\uD68D \uAE30\uB2A5 \uC2E4\uD5D8\uC801 \uD65C\uC131\uD654",
|
|
1039
|
-
patch: { experimental: { jitContext: true, plan: true } }
|
|
1040
|
-
}
|
|
1041
|
-
];
|
|
1042
|
-
var promptGeminiSettings = async () => {
|
|
1043
|
-
const wantSettings = await p.confirm({
|
|
1044
|
-
message: "Gemini CLI \uC124\uC815 \uD30C\uC77C(.gemini/settings.json)\uC744 \uC124\uCE58\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
|
|
1045
|
-
initialValue: true
|
|
1046
|
-
});
|
|
1047
|
-
if (p.isCancel(wantSettings)) return PROMPT_CANCELLED;
|
|
1048
|
-
if (!wantSettings) return null;
|
|
1052
|
+
// src/lib/tool-settings.ts
|
|
1053
|
+
var promptToolSettings = async (config) => {
|
|
1054
|
+
const want = await p.confirm({ message: config.promptMessage, initialValue: true });
|
|
1055
|
+
if (p.isCancel(want)) return PROMPT_CANCELLED;
|
|
1056
|
+
if (!want) return null;
|
|
1049
1057
|
const selected = await p.multiselect({
|
|
1050
1058
|
message: "\uC124\uCE58\uD560 \uC124\uC815 \uD56D\uBAA9\uC744 \uC120\uD0DD\uD558\uC138\uC694 (\uC2A4\uD398\uC774\uC2A4\uB85C \uD1A0\uAE00)",
|
|
1051
|
-
options:
|
|
1052
|
-
|
|
1053
|
-
label: g.label,
|
|
1054
|
-
hint: g.hint
|
|
1055
|
-
})),
|
|
1056
|
-
initialValues: SETTING_GROUPS.map((g) => g.value),
|
|
1059
|
+
options: config.groups.map((g) => ({ value: g.value, label: g.label, hint: g.hint })),
|
|
1060
|
+
initialValues: config.groups.map((g) => g.value),
|
|
1057
1061
|
required: false
|
|
1058
1062
|
});
|
|
1059
1063
|
if (p.isCancel(selected)) return PROMPT_CANCELLED;
|
|
1060
1064
|
return selected;
|
|
1061
1065
|
};
|
|
1062
|
-
var
|
|
1066
|
+
var installToolSettings = (basePath, selectedValues, config) => {
|
|
1063
1067
|
if (selectedValues.length === 0) return;
|
|
1064
|
-
const settingsDir = join11(basePath,
|
|
1065
|
-
const settingsPath = join11(settingsDir,
|
|
1068
|
+
const settingsDir = join11(basePath, config.dirName);
|
|
1069
|
+
const settingsPath = join11(settingsDir, config.fileName);
|
|
1066
1070
|
let existing = {};
|
|
1067
1071
|
if (existsSync5(settingsPath)) {
|
|
1068
1072
|
try {
|
|
@@ -1072,15 +1076,15 @@ var installGeminiSettings = (basePath, selectedValues) => {
|
|
|
1072
1076
|
}
|
|
1073
1077
|
let merged = existing;
|
|
1074
1078
|
for (const val of selectedValues) {
|
|
1075
|
-
const group =
|
|
1079
|
+
const group = config.groups.find((g) => g.value === val);
|
|
1076
1080
|
if (!group) continue;
|
|
1077
1081
|
merged = deepMerge(merged, group.patch);
|
|
1078
1082
|
}
|
|
1079
1083
|
mkdirSync5(settingsDir, { recursive: true });
|
|
1080
1084
|
writeFileSync5(settingsPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
1081
1085
|
};
|
|
1082
|
-
var
|
|
1083
|
-
const settingsPath = join11(basePath,
|
|
1086
|
+
var uninstallToolSettings = (basePath, selectedValues, config) => {
|
|
1087
|
+
const settingsPath = join11(basePath, config.dirName, config.fileName);
|
|
1084
1088
|
if (!existsSync5(settingsPath)) return "notFound";
|
|
1085
1089
|
let existing = {};
|
|
1086
1090
|
try {
|
|
@@ -1091,12 +1095,9 @@ var uninstallGeminiSettings = (basePath, selectedValues) => {
|
|
|
1091
1095
|
}
|
|
1092
1096
|
let result = existing;
|
|
1093
1097
|
for (const val of selectedValues) {
|
|
1094
|
-
const group =
|
|
1098
|
+
const group = config.groups.find((g) => g.value === val);
|
|
1095
1099
|
if (!group) continue;
|
|
1096
|
-
result = deepRemoveKeys(
|
|
1097
|
-
result,
|
|
1098
|
-
group.patch
|
|
1099
|
-
);
|
|
1100
|
+
result = deepRemoveKeys(result, group.patch);
|
|
1100
1101
|
}
|
|
1101
1102
|
if (Object.keys(result).length === 0) {
|
|
1102
1103
|
rmSync2(settingsPath, { force: true });
|
|
@@ -1106,10 +1107,44 @@ var uninstallGeminiSettings = (basePath, selectedValues) => {
|
|
|
1106
1107
|
return "cleaned";
|
|
1107
1108
|
};
|
|
1108
1109
|
|
|
1110
|
+
// src/lib/gemini-settings.ts
|
|
1111
|
+
var SETTING_GROUPS = [
|
|
1112
|
+
{
|
|
1113
|
+
value: "ui",
|
|
1114
|
+
label: "UI \u2014 \uC904 \uBC88\uD638 \uC228\uAE30\uAE30",
|
|
1115
|
+
hint: "ui.showLineNumbers: false \u2014 \uCF54\uB4DC \uBCF5\uC0AC \uC2DC \uC904 \uBC88\uD638\uAC00 \uD3EC\uD568\uB418\uC9C0 \uC54A\uB3C4\uB85D \uBE44\uD65C\uC131\uD654",
|
|
1116
|
+
patch: { ui: { showLineNumbers: false } }
|
|
1117
|
+
},
|
|
1118
|
+
{
|
|
1119
|
+
value: "plan",
|
|
1120
|
+
label: "Plan \u2014 \uACC4\uD68D \uD30C\uC77C \uC800\uC7A5 \uBC0F \uBAA8\uB378 \uB77C\uC6B0\uD305",
|
|
1121
|
+
hint: "general.plan.directory: .gemini/plans, modelRouting: true \u2014 AI \uACC4\uD68D\uC744 \uD30C\uC77C\uB85C \uC800\uC7A5\uD558\uACE0 \uD0DC\uC2A4\uD06C\uBCC4 \uCD5C\uC801 \uBAA8\uB378 \uC790\uB3D9 \uC120\uD0DD",
|
|
1122
|
+
patch: { general: { plan: { directory: ".gemini/plans", modelRouting: true } } }
|
|
1123
|
+
},
|
|
1124
|
+
{
|
|
1125
|
+
value: "sessionRetention",
|
|
1126
|
+
label: "Session Retention \u2014 \uC138\uC158 30\uC77C \uBCF4\uC874",
|
|
1127
|
+
hint: "general.sessionRetention.maxAge: 30d \u2014 \uC774\uC804 \uB300\uD654 \uCEE8\uD14D\uC2A4\uD2B8\uB97C 30\uC77C\uAC04 \uC720\uC9C0",
|
|
1128
|
+
patch: { general: { sessionRetention: { maxAge: "30d" } } }
|
|
1129
|
+
},
|
|
1130
|
+
{
|
|
1131
|
+
value: "experimental",
|
|
1132
|
+
label: "Experimental \u2014 JIT \uCEE8\uD14D\uC2A4\uD2B8 + Plan \uAE30\uB2A5",
|
|
1133
|
+
hint: "experimental.jitContext: true, plan: true \u2014 \uC11C\uBE0C\uB514\uB809\uD1A0\uB9AC \uCEE8\uD14D\uC2A4\uD2B8 \uC9C0\uC5F0 \uB85C\uB529 \uBC0F \uACC4\uD68D \uAE30\uB2A5 \uC2E4\uD5D8\uC801 \uD65C\uC131\uD654",
|
|
1134
|
+
patch: { experimental: { jitContext: true, plan: true } }
|
|
1135
|
+
}
|
|
1136
|
+
];
|
|
1137
|
+
var CONFIG = {
|
|
1138
|
+
dirName: ".gemini",
|
|
1139
|
+
fileName: "settings.json",
|
|
1140
|
+
promptMessage: "Gemini CLI \uC124\uC815 \uD30C\uC77C(.gemini/settings.json)\uC744 \uC124\uCE58\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
|
|
1141
|
+
groups: SETTING_GROUPS
|
|
1142
|
+
};
|
|
1143
|
+
var promptGeminiSettings = () => promptToolSettings(CONFIG);
|
|
1144
|
+
var installGeminiSettings = (basePath, selectedValues) => installToolSettings(basePath, selectedValues, CONFIG);
|
|
1145
|
+
var uninstallGeminiSettings = (basePath, selectedValues) => uninstallToolSettings(basePath, selectedValues, CONFIG);
|
|
1146
|
+
|
|
1109
1147
|
// src/lib/claude-settings.ts
|
|
1110
|
-
import * as p2 from "@clack/prompts";
|
|
1111
|
-
import { existsSync as existsSync6, mkdirSync as mkdirSync6, readFileSync as readFileSync7, rmSync as rmSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
1112
|
-
import { join as join12 } from "path";
|
|
1113
1148
|
var SETTING_GROUPS2 = [
|
|
1114
1149
|
{
|
|
1115
1150
|
value: "model",
|
|
@@ -1124,77 +1159,20 @@ var SETTING_GROUPS2 = [
|
|
|
1124
1159
|
patch: { plansDirectory: "./.claude/plans" }
|
|
1125
1160
|
}
|
|
1126
1161
|
];
|
|
1127
|
-
var
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
options: SETTING_GROUPS2.map((g) => ({
|
|
1137
|
-
value: g.value,
|
|
1138
|
-
label: g.label,
|
|
1139
|
-
hint: g.hint
|
|
1140
|
-
})),
|
|
1141
|
-
initialValues: SETTING_GROUPS2.map((g) => g.value),
|
|
1142
|
-
required: false
|
|
1143
|
-
});
|
|
1144
|
-
if (p2.isCancel(selected)) return PROMPT_CANCELLED;
|
|
1145
|
-
return selected;
|
|
1146
|
-
};
|
|
1147
|
-
var installClaudeSettings = (basePath, selectedValues) => {
|
|
1148
|
-
if (selectedValues.length === 0) return;
|
|
1149
|
-
const settingsDir = join12(basePath, ".claude");
|
|
1150
|
-
const settingsPath = join12(settingsDir, "settings.local.json");
|
|
1151
|
-
let existing = {};
|
|
1152
|
-
if (existsSync6(settingsPath)) {
|
|
1153
|
-
try {
|
|
1154
|
-
existing = JSON.parse(readFileSync7(settingsPath, "utf-8"));
|
|
1155
|
-
} catch {
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
let merged = existing;
|
|
1159
|
-
for (const val of selectedValues) {
|
|
1160
|
-
const group = SETTING_GROUPS2.find((g) => g.value === val);
|
|
1161
|
-
if (!group) continue;
|
|
1162
|
-
merged = deepMerge(merged, group.patch);
|
|
1163
|
-
}
|
|
1164
|
-
mkdirSync6(settingsDir, { recursive: true });
|
|
1165
|
-
writeFileSync6(settingsPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
1166
|
-
};
|
|
1167
|
-
var uninstallClaudeSettings = (basePath, selectedValues) => {
|
|
1168
|
-
const settingsPath = join12(basePath, ".claude", "settings.local.json");
|
|
1169
|
-
if (!existsSync6(settingsPath)) return "notFound";
|
|
1170
|
-
let existing = {};
|
|
1171
|
-
try {
|
|
1172
|
-
existing = JSON.parse(readFileSync7(settingsPath, "utf-8"));
|
|
1173
|
-
} catch {
|
|
1174
|
-
rmSync3(settingsPath, { force: true });
|
|
1175
|
-
return "deleted";
|
|
1176
|
-
}
|
|
1177
|
-
let result = existing;
|
|
1178
|
-
for (const val of selectedValues) {
|
|
1179
|
-
const group = SETTING_GROUPS2.find((g) => g.value === val);
|
|
1180
|
-
if (!group) continue;
|
|
1181
|
-
result = deepRemoveKeys(
|
|
1182
|
-
result,
|
|
1183
|
-
group.patch
|
|
1184
|
-
);
|
|
1185
|
-
}
|
|
1186
|
-
if (Object.keys(result).length === 0) {
|
|
1187
|
-
rmSync3(settingsPath, { force: true });
|
|
1188
|
-
return "deleted";
|
|
1189
|
-
}
|
|
1190
|
-
writeFileSync6(settingsPath, JSON.stringify(result, null, 2) + "\n", "utf-8");
|
|
1191
|
-
return "cleaned";
|
|
1192
|
-
};
|
|
1162
|
+
var CONFIG2 = {
|
|
1163
|
+
dirName: ".claude",
|
|
1164
|
+
fileName: "settings.local.json",
|
|
1165
|
+
promptMessage: "Claude Code \uC124\uC815 \uD30C\uC77C(.claude/settings.local.json)\uC744 \uC124\uCE58\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
|
|
1166
|
+
groups: SETTING_GROUPS2
|
|
1167
|
+
};
|
|
1168
|
+
var promptClaudeSettings = () => promptToolSettings(CONFIG2);
|
|
1169
|
+
var installClaudeSettings = (basePath, selectedValues) => installToolSettings(basePath, selectedValues, CONFIG2);
|
|
1170
|
+
var uninstallClaudeSettings = (basePath, selectedValues) => uninstallToolSettings(basePath, selectedValues, CONFIG2);
|
|
1193
1171
|
|
|
1194
1172
|
// src/lib/prettier-ignore.ts
|
|
1195
|
-
import * as
|
|
1196
|
-
import { existsSync as
|
|
1197
|
-
import { join as
|
|
1173
|
+
import * as p2 from "@clack/prompts";
|
|
1174
|
+
import { existsSync as existsSync6, readFileSync as readFileSync7, rmSync as rmSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
1175
|
+
import { join as join12 } from "path";
|
|
1198
1176
|
var PRETTIER_IGNORE_CONTENT = `# CLAUDE
|
|
1199
1177
|
.claude/rules/
|
|
1200
1178
|
**/CLAUDE.md
|
|
@@ -1252,39 +1230,39 @@ var stripAiOpsSection2 = (content) => {
|
|
|
1252
1230
|
return result.join("\n");
|
|
1253
1231
|
};
|
|
1254
1232
|
var promptPrettierIgnore = async () => {
|
|
1255
|
-
const want = await
|
|
1233
|
+
const want = await p2.confirm({
|
|
1256
1234
|
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)",
|
|
1257
1235
|
initialValue: false
|
|
1258
1236
|
});
|
|
1259
|
-
if (
|
|
1237
|
+
if (p2.isCancel(want)) return PROMPT_CANCELLED;
|
|
1260
1238
|
return want;
|
|
1261
1239
|
};
|
|
1262
1240
|
var installPrettierIgnore = (basePath) => {
|
|
1263
|
-
const filePath =
|
|
1241
|
+
const filePath = join12(basePath, ".prettierignore");
|
|
1264
1242
|
const section = wrapSection(PRETTIER_IGNORE_CONTENT);
|
|
1265
|
-
if (!
|
|
1266
|
-
|
|
1243
|
+
if (!existsSync6(filePath)) {
|
|
1244
|
+
writeFileSync6(filePath, section + "\n", "utf-8");
|
|
1267
1245
|
return;
|
|
1268
1246
|
}
|
|
1269
|
-
const existing =
|
|
1247
|
+
const existing = readFileSync7(filePath, "utf-8");
|
|
1270
1248
|
if (hasAiOpsSection2(existing)) {
|
|
1271
|
-
|
|
1249
|
+
writeFileSync6(filePath, replaceSection(existing, PRETTIER_IGNORE_CONTENT), "utf-8");
|
|
1272
1250
|
return;
|
|
1273
1251
|
}
|
|
1274
1252
|
const separator = existing.endsWith("\n") ? "\n" : "\n\n";
|
|
1275
|
-
|
|
1253
|
+
writeFileSync6(filePath, existing + separator + section + "\n", "utf-8");
|
|
1276
1254
|
};
|
|
1277
1255
|
var uninstallPrettierIgnore = (basePath) => {
|
|
1278
|
-
const filePath =
|
|
1279
|
-
if (!
|
|
1280
|
-
const existing =
|
|
1256
|
+
const filePath = join12(basePath, ".prettierignore");
|
|
1257
|
+
if (!existsSync6(filePath)) return "notFound";
|
|
1258
|
+
const existing = readFileSync7(filePath, "utf-8");
|
|
1281
1259
|
if (!hasAiOpsSection2(existing)) return "notFound";
|
|
1282
1260
|
const stripped = stripAiOpsSection2(existing).trim();
|
|
1283
1261
|
if (stripped.length === 0) {
|
|
1284
|
-
|
|
1262
|
+
rmSync3(filePath, { force: true });
|
|
1285
1263
|
return "deleted";
|
|
1286
1264
|
}
|
|
1287
|
-
|
|
1265
|
+
writeFileSync6(filePath, stripped + "\n", "utf-8");
|
|
1288
1266
|
return "cleaned";
|
|
1289
1267
|
};
|
|
1290
1268
|
|
|
@@ -1405,7 +1383,7 @@ var partitionPresetSkills = (params) => {
|
|
|
1405
1383
|
};
|
|
1406
1384
|
};
|
|
1407
1385
|
var selectPresetAndFineTune = async (workspaceName, presets, allRules, allSkills, selectedTools, globalInstalledSkills) => {
|
|
1408
|
-
const preset = await
|
|
1386
|
+
const preset = await p3.select({
|
|
1409
1387
|
message: `[${workspaceName}] \uD504\uB9AC\uC14B\uC744 \uC120\uD0DD\uD558\uC138\uC694`,
|
|
1410
1388
|
options: presets.map((candidate) => ({
|
|
1411
1389
|
value: candidate,
|
|
@@ -1413,10 +1391,10 @@ var selectPresetAndFineTune = async (workspaceName, presets, allRules, allSkills
|
|
|
1413
1391
|
hint: candidate.description
|
|
1414
1392
|
}))
|
|
1415
1393
|
});
|
|
1416
|
-
if (
|
|
1394
|
+
if (p3.isCancel(preset)) return null;
|
|
1417
1395
|
const finalRules = resolvePresetRules(preset, allRules);
|
|
1418
1396
|
if (finalRules.length > 0) {
|
|
1419
|
-
|
|
1397
|
+
p3.note(finalRules.map((rule) => ` \u2713 ${rule.id}`).join("\n"), `[${workspaceName}] core rules (\uC7A0\uAE08)`);
|
|
1420
1398
|
}
|
|
1421
1399
|
const { globalSkills, installableSkills } = partitionPresetSkills({
|
|
1422
1400
|
preset,
|
|
@@ -1428,10 +1406,10 @@ var selectPresetAndFineTune = async (workspaceName, presets, allRules, allSkills
|
|
|
1428
1406
|
const globalLines = globalSkills.map(
|
|
1429
1407
|
({ skill, availableTools }) => ` \u2713 ${skill.id} (${formatToolList(availableTools)})`
|
|
1430
1408
|
);
|
|
1431
|
-
|
|
1409
|
+
p3.note(globalLines.join("\n"), `[${workspaceName}] already available globally`);
|
|
1432
1410
|
}
|
|
1433
1411
|
if (installableSkills.length === 0) {
|
|
1434
|
-
|
|
1412
|
+
p3.note(" \uC0C8\uB85C \uC124\uCE58\uD560 reference skill\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.", `[${workspaceName}] installable reference skills`);
|
|
1435
1413
|
return {
|
|
1436
1414
|
workspace: workspaceName,
|
|
1437
1415
|
preset,
|
|
@@ -1439,7 +1417,7 @@ var selectPresetAndFineTune = async (workspaceName, presets, allRules, allSkills
|
|
|
1439
1417
|
finalSkillTargets: []
|
|
1440
1418
|
};
|
|
1441
1419
|
}
|
|
1442
|
-
const selectedSkillIds = await
|
|
1420
|
+
const selectedSkillIds = await p3.multiselect({
|
|
1443
1421
|
message: `[${workspaceName}] installable reference skills \uC120\uD0DD`,
|
|
1444
1422
|
options: installableSkills.map(({ skill, requestedTools, globalTools }) => ({
|
|
1445
1423
|
value: skill.id,
|
|
@@ -1449,7 +1427,7 @@ var selectPresetAndFineTune = async (workspaceName, presets, allRules, allSkills
|
|
|
1449
1427
|
initialValues: installableSkills.map(({ skill }) => skill.id),
|
|
1450
1428
|
required: false
|
|
1451
1429
|
});
|
|
1452
|
-
if (
|
|
1430
|
+
if (p3.isCancel(selectedSkillIds)) return null;
|
|
1453
1431
|
const selectedSkillSet = new Set(selectedSkillIds);
|
|
1454
1432
|
return {
|
|
1455
1433
|
workspace: workspaceName,
|
|
@@ -1462,28 +1440,28 @@ var selectPresetAndFineTune = async (workspaceName, presets, allRules, allSkills
|
|
|
1462
1440
|
};
|
|
1463
1441
|
};
|
|
1464
1442
|
var selectInitSkillScope = async () => {
|
|
1465
|
-
const scope = await
|
|
1443
|
+
const scope = await p3.select({
|
|
1466
1444
|
message: "\uC120\uD0DD\uB41C skills\uB97C \uC5B4\uB514\uC5D0 \uC124\uCE58\uD560\uAE4C\uC694?",
|
|
1467
1445
|
options: [
|
|
1468
1446
|
{ value: "user", label: "user (global)", hint: "\uAE30\uBCF8\uAC12. \uC5EC\uB7EC \uD504\uB85C\uC81D\uD2B8\uC5D0\uC11C \uC7AC\uC0AC\uC6A9" },
|
|
1469
1447
|
{ value: "project", label: "project", hint: "\uD604\uC7AC \uD504\uB85C\uC81D\uD2B8\uC5D0\uB9CC \uC124\uCE58" }
|
|
1470
1448
|
]
|
|
1471
1449
|
});
|
|
1472
|
-
return
|
|
1450
|
+
return p3.isCancel(scope) ? null : scope;
|
|
1473
1451
|
};
|
|
1474
1452
|
var initCommand = async () => {
|
|
1475
1453
|
const basePath = resolveBasePath();
|
|
1476
1454
|
const userBasePath = resolveUserBasePath();
|
|
1477
1455
|
const rulesDir = resolveRulesDir();
|
|
1478
1456
|
const skillsDir = resolveSkillsDir();
|
|
1479
|
-
const spinner3 =
|
|
1457
|
+
const spinner3 = p3.spinner();
|
|
1480
1458
|
let spinnerStarted = false;
|
|
1481
1459
|
const cancelInit = (params) => {
|
|
1482
1460
|
if (spinnerStarted) {
|
|
1483
1461
|
spinner3.stop("\uC124\uCE58 \uC911\uB2E8\uB428");
|
|
1484
1462
|
spinnerStarted = false;
|
|
1485
1463
|
}
|
|
1486
|
-
|
|
1464
|
+
p3.cancel(params?.message ?? "\uCDE8\uC18C\uB428");
|
|
1487
1465
|
process.exit(params?.exitCode ?? 0);
|
|
1488
1466
|
};
|
|
1489
1467
|
const handleSigint = () => cancelInit({
|
|
@@ -1492,20 +1470,20 @@ var initCommand = async () => {
|
|
|
1492
1470
|
});
|
|
1493
1471
|
process.once("SIGINT", handleSigint);
|
|
1494
1472
|
try {
|
|
1495
|
-
|
|
1496
|
-
const selectedTools = await
|
|
1473
|
+
p3.intro("ai-ops init");
|
|
1474
|
+
const selectedTools = await p3.multiselect({
|
|
1497
1475
|
message: "AI \uB3C4\uAD6C\uB97C \uC120\uD0DD\uD558\uC138\uC694",
|
|
1498
1476
|
options: TOOL_OPTIONS,
|
|
1499
1477
|
required: true
|
|
1500
1478
|
});
|
|
1501
|
-
if (
|
|
1479
|
+
if (p3.isCancel(selectedTools)) {
|
|
1502
1480
|
cancelInit();
|
|
1503
1481
|
}
|
|
1504
|
-
const isMonorepo = await
|
|
1482
|
+
const isMonorepo = await p3.confirm({
|
|
1505
1483
|
message: "\uBAA8\uB178\uB808\uD3EC \uD504\uB85C\uC81D\uD2B8\uC785\uB2C8\uAE4C?",
|
|
1506
1484
|
initialValue: false
|
|
1507
1485
|
});
|
|
1508
|
-
if (
|
|
1486
|
+
if (p3.isCancel(isMonorepo)) {
|
|
1509
1487
|
cancelInit();
|
|
1510
1488
|
}
|
|
1511
1489
|
const allRules = loadAllRules(rulesDir);
|
|
@@ -1526,12 +1504,12 @@ var initCommand = async () => {
|
|
|
1526
1504
|
mappings.push(mapping);
|
|
1527
1505
|
} else {
|
|
1528
1506
|
const candidates = listWorkspaceCandidates(basePath);
|
|
1529
|
-
const selectedWorkspaces = await
|
|
1507
|
+
const selectedWorkspaces = await p3.multiselect({
|
|
1530
1508
|
message: "\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4\uB97C \uC120\uD0DD\uD558\uC138\uC694",
|
|
1531
1509
|
options: candidates.map((candidate) => ({ value: candidate, label: candidate })),
|
|
1532
1510
|
required: true
|
|
1533
1511
|
});
|
|
1534
|
-
if (
|
|
1512
|
+
if (p3.isCancel(selectedWorkspaces)) {
|
|
1535
1513
|
cancelInit();
|
|
1536
1514
|
}
|
|
1537
1515
|
for (const workspace of selectedWorkspaces) {
|
|
@@ -1655,29 +1633,29 @@ var initCommand = async () => {
|
|
|
1655
1633
|
});
|
|
1656
1634
|
writeManifest(resolveManifestPath(basePath), manifest);
|
|
1657
1635
|
if (allAppended.length > 0) {
|
|
1658
|
-
|
|
1636
|
+
p3.log.info(`\uAE30\uC874 \uD30C\uC77C\uC5D0 \uC139\uC158 \uCD94\uAC00\uB428 (\uB0B4\uC6A9 \uBCF4\uC874):
|
|
1659
1637
|
${allAppended.map((file) => ` ${file}`).join("\n")}`);
|
|
1660
1638
|
}
|
|
1661
|
-
|
|
1662
|
-
|
|
1639
|
+
p3.log.success(`\uC124\uCE58\uB41C core rules: ${selectedRuleIds.length}\uAC1C`);
|
|
1640
|
+
p3.log.success(`\uC124\uCE58\uB41C skills: ${selectedSkillTargets.length}\uAC1C${skillScope ? ` (${skillScope})` : ""}`);
|
|
1663
1641
|
if (selectedSkillTargets.length > 0 && skillScope === "user") {
|
|
1664
|
-
|
|
1642
|
+
p3.log.info("global skill\uC740 ai-ops uninstall \uB300\uC0C1\uC774 \uC544\uB2D9\uB2C8\uB2E4. ai-ops skill uninstall\uC73C\uB85C \uC81C\uAC70\uD558\uC138\uC694.");
|
|
1665
1643
|
}
|
|
1666
|
-
|
|
1644
|
+
p3.outro("ai-ops init \uC644\uB8CC");
|
|
1667
1645
|
} finally {
|
|
1668
1646
|
process.off("SIGINT", handleSigint);
|
|
1669
1647
|
}
|
|
1670
1648
|
};
|
|
1671
1649
|
|
|
1672
1650
|
// src/commands/update.ts
|
|
1673
|
-
import * as
|
|
1651
|
+
import * as p4 from "@clack/prompts";
|
|
1674
1652
|
var updateCommand = async (opts) => {
|
|
1675
1653
|
const basePath = resolveBasePath();
|
|
1676
1654
|
const manifestPath = resolveManifestPath(basePath);
|
|
1677
|
-
|
|
1655
|
+
p4.intro("ai-ops update");
|
|
1678
1656
|
const manifest = readManifest(manifestPath);
|
|
1679
1657
|
if (!manifest) {
|
|
1680
|
-
|
|
1658
|
+
p4.log.error("manifest\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. \uBA3C\uC800 ai-ops init\uC744 \uC2E4\uD589\uD558\uC138\uC694.");
|
|
1681
1659
|
process.exit(1);
|
|
1682
1660
|
}
|
|
1683
1661
|
const rulesDir = resolveRulesDir();
|
|
@@ -1704,11 +1682,11 @@ var updateCommand = async (opts) => {
|
|
|
1704
1682
|
currentCliVersion: cliVersion
|
|
1705
1683
|
});
|
|
1706
1684
|
if (diffResult.status === "up-to-date" && !opts.force) {
|
|
1707
|
-
|
|
1708
|
-
|
|
1685
|
+
p4.log.info("\uBCC0\uACBD \uC0AC\uD56D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
1686
|
+
p4.outro("ai-ops update \uC644\uB8CC");
|
|
1709
1687
|
return;
|
|
1710
1688
|
}
|
|
1711
|
-
const s =
|
|
1689
|
+
const s = p4.spinner();
|
|
1712
1690
|
s.start("\uADDC\uCE59 \uAC31\uC2E0 \uC911...");
|
|
1713
1691
|
const meta = { sourceHash, generatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
1714
1692
|
const allInstalledFiles = [];
|
|
@@ -1776,17 +1754,17 @@ var updateCommand = async (opts) => {
|
|
|
1776
1754
|
});
|
|
1777
1755
|
writeManifest(manifestPath, newManifest);
|
|
1778
1756
|
s.stop("\uADDC\uCE59 \uAC31\uC2E0 \uC644\uB8CC");
|
|
1779
|
-
|
|
1757
|
+
p4.outro("ai-ops update \uC644\uB8CC");
|
|
1780
1758
|
};
|
|
1781
1759
|
|
|
1782
1760
|
// src/commands/diff.ts
|
|
1783
|
-
import * as
|
|
1761
|
+
import * as p5 from "@clack/prompts";
|
|
1784
1762
|
var diffCommand = async () => {
|
|
1785
1763
|
const basePath = resolveBasePath();
|
|
1786
|
-
|
|
1764
|
+
p5.intro("ai-ops diff");
|
|
1787
1765
|
const manifest = readManifest(resolveManifestPath(basePath));
|
|
1788
1766
|
if (!manifest) {
|
|
1789
|
-
|
|
1767
|
+
p5.log.error("manifest\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. \uBA3C\uC800 ai-ops init\uC744 \uC2E4\uD589\uD558\uC138\uC694.");
|
|
1790
1768
|
process.exit(1);
|
|
1791
1769
|
}
|
|
1792
1770
|
const sourceHash = computeSourceHash(resolveCompilerDataDir());
|
|
@@ -1819,31 +1797,31 @@ var diffCommand = async () => {
|
|
|
1819
1797
|
return `- ${skill.id}: ${changed ? "changed" : "up-to-date"} (${previousHash} -> ${next.sourceHash})`;
|
|
1820
1798
|
});
|
|
1821
1799
|
if (result.status === "up-to-date") {
|
|
1822
|
-
|
|
1800
|
+
p5.log.success("\uBCC0\uACBD \uC0AC\uD56D \uC5C6\uC74C. \uCD5C\uC2E0 \uC0C1\uD0DC\uC785\uB2C8\uB2E4.");
|
|
1823
1801
|
} else {
|
|
1824
1802
|
if (result.sourceChanged) {
|
|
1825
|
-
|
|
1803
|
+
p5.log.warn(`\uC18C\uC2A4 \uBCC0\uACBD \uAC10\uC9C0: ${manifest.sourceHash} \u2192 ${sourceHash}`);
|
|
1826
1804
|
}
|
|
1827
1805
|
if (result.added.length > 0) {
|
|
1828
|
-
|
|
1806
|
+
p5.log.info(`\uCD94\uAC00\uB41C \uADDC\uCE59: ${result.added.join(", ")}`);
|
|
1829
1807
|
}
|
|
1830
1808
|
if (result.removed.length > 0) {
|
|
1831
|
-
|
|
1809
|
+
p5.log.info(`\uC81C\uAC70\uB41C \uADDC\uCE59: ${result.removed.join(", ")}`);
|
|
1832
1810
|
}
|
|
1833
1811
|
}
|
|
1834
1812
|
if (skillLines.length > 0) {
|
|
1835
|
-
|
|
1813
|
+
p5.log.info(`project skills:
|
|
1836
1814
|
${skillLines.map((line) => ` ${line}`).join("\n")}`);
|
|
1837
1815
|
}
|
|
1838
|
-
|
|
1816
|
+
p5.outro("ai-ops diff \uC644\uB8CC");
|
|
1839
1817
|
};
|
|
1840
1818
|
|
|
1841
1819
|
// src/commands/uninstall.ts
|
|
1842
|
-
import * as
|
|
1843
|
-
import { rmSync as
|
|
1820
|
+
import * as p6 from "@clack/prompts";
|
|
1821
|
+
import { rmSync as rmSync5 } from "fs";
|
|
1844
1822
|
|
|
1845
1823
|
// src/lib/uninstall.ts
|
|
1846
|
-
import { existsSync as
|
|
1824
|
+
import { existsSync as existsSync7, readFileSync as readFileSync8, rmSync as rmSync4, readdirSync as readdirSync4, writeFileSync as writeFileSync7 } from "fs";
|
|
1847
1825
|
import { resolve as resolve7, dirname as dirname7 } from "path";
|
|
1848
1826
|
var removeFiles = (basePath, relativePaths) => {
|
|
1849
1827
|
const deleted = [];
|
|
@@ -1852,22 +1830,22 @@ var removeFiles = (basePath, relativePaths) => {
|
|
|
1852
1830
|
const notFound = [];
|
|
1853
1831
|
for (const rel of relativePaths) {
|
|
1854
1832
|
const absPath = resolve7(basePath, rel);
|
|
1855
|
-
if (!
|
|
1833
|
+
if (!existsSync7(absPath)) {
|
|
1856
1834
|
notFound.push(rel);
|
|
1857
1835
|
continue;
|
|
1858
1836
|
}
|
|
1859
|
-
const content =
|
|
1837
|
+
const content = readFileSync8(absPath, "utf-8");
|
|
1860
1838
|
if (hasAiOpsSection(content)) {
|
|
1861
1839
|
const stripped = stripAiOpsSection(content);
|
|
1862
1840
|
if (stripped.trim().length === 0) {
|
|
1863
|
-
|
|
1841
|
+
rmSync4(absPath);
|
|
1864
1842
|
deleted.push(rel);
|
|
1865
1843
|
} else {
|
|
1866
|
-
|
|
1844
|
+
writeFileSync7(absPath, stripped, "utf-8");
|
|
1867
1845
|
cleaned.push(rel);
|
|
1868
1846
|
}
|
|
1869
1847
|
} else if (hasLegacyHeader(content)) {
|
|
1870
|
-
|
|
1848
|
+
rmSync4(absPath);
|
|
1871
1849
|
deleted.push(rel);
|
|
1872
1850
|
} else {
|
|
1873
1851
|
skipped.push(rel);
|
|
@@ -1879,11 +1857,11 @@ var cleanEmptyDirs = (basePath, dirs) => {
|
|
|
1879
1857
|
const removed = [];
|
|
1880
1858
|
for (const dir of dirs) {
|
|
1881
1859
|
const absDir = resolve7(basePath, dir);
|
|
1882
|
-
if (!
|
|
1860
|
+
if (!existsSync7(absDir)) continue;
|
|
1883
1861
|
try {
|
|
1884
1862
|
const entries = readdirSync4(absDir);
|
|
1885
1863
|
if (entries.length === 0) {
|
|
1886
|
-
|
|
1864
|
+
rmSync4(absDir, { recursive: true });
|
|
1887
1865
|
removed.push(dir);
|
|
1888
1866
|
}
|
|
1889
1867
|
} catch {
|
|
@@ -1907,10 +1885,10 @@ var SETTINGS_PATHS = /* @__PURE__ */ new Set([".claude/settings.local.json", ".g
|
|
|
1907
1885
|
var uninstallCommand = async () => {
|
|
1908
1886
|
const basePath = resolveBasePath();
|
|
1909
1887
|
const manifestPath = resolveManifestPath(basePath);
|
|
1910
|
-
|
|
1888
|
+
p6.intro("ai-ops uninstall");
|
|
1911
1889
|
const manifest = readManifest(manifestPath);
|
|
1912
1890
|
if (!manifest) {
|
|
1913
|
-
|
|
1891
|
+
p6.log.error("manifest\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. \uBA3C\uC800 ai-ops init\uC744 \uC2E4\uD589\uD558\uC138\uC694.");
|
|
1914
1892
|
process.exit(1);
|
|
1915
1893
|
}
|
|
1916
1894
|
const targetFiles = [
|
|
@@ -1919,31 +1897,34 @@ var uninstallCommand = async () => {
|
|
|
1919
1897
|
].filter((f) => !SETTINGS_PATHS.has(f));
|
|
1920
1898
|
const targetSkillDirs = (manifest.installed_skills ?? []).flatMap((skill) => skill.installed_paths);
|
|
1921
1899
|
if (targetFiles.length === 0 && targetSkillDirs.length === 0) {
|
|
1922
|
-
|
|
1923
|
-
|
|
1900
|
+
p6.log.warn("\uC0AD\uC81C\uD560 \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
1901
|
+
p6.outro("ai-ops uninstall \uC644\uB8CC");
|
|
1924
1902
|
return;
|
|
1925
1903
|
}
|
|
1926
1904
|
if (targetFiles.length > 0) {
|
|
1927
|
-
|
|
1905
|
+
p6.log.info(`\uC0AD\uC81C \uB300\uC0C1 \uD30C\uC77C (${targetFiles.length}\uAC1C):
|
|
1928
1906
|
${targetFiles.map((f) => ` ${f}`).join("\n")}`);
|
|
1929
1907
|
}
|
|
1930
1908
|
if (targetSkillDirs.length > 0) {
|
|
1931
|
-
|
|
1932
|
-
${targetSkillDirs.
|
|
1909
|
+
p6.log.info(
|
|
1910
|
+
`\uC0AD\uC81C \uB300\uC0C1 skill \uB514\uB809\uD1A0\uB9AC (${targetSkillDirs.length}\uAC1C):
|
|
1911
|
+
${targetSkillDirs.map((f) => ` ${f}`).join("\n")}`
|
|
1912
|
+
);
|
|
1933
1913
|
}
|
|
1934
|
-
const confirmed = await
|
|
1914
|
+
const confirmed = await p6.confirm({
|
|
1935
1915
|
message: "\uC704 \uD30C\uC77C\uACFC manifest\uB97C \uBAA8\uB450 \uC0AD\uC81C\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
|
|
1936
1916
|
initialValue: false
|
|
1937
1917
|
});
|
|
1938
|
-
if (
|
|
1939
|
-
|
|
1918
|
+
if (p6.isCancel(confirmed) || !confirmed) {
|
|
1919
|
+
p6.cancel("\uCDE8\uC18C\uB428");
|
|
1940
1920
|
process.exit(0);
|
|
1941
1921
|
}
|
|
1942
1922
|
const settingsMessages = [];
|
|
1943
1923
|
if (manifest.settings?.claude) {
|
|
1944
1924
|
const status = uninstallClaudeSettings(basePath, manifest.settings.claude);
|
|
1945
1925
|
if (status === "deleted") settingsMessages.push("\uC0AD\uC81C: .claude/settings.local.json");
|
|
1946
|
-
else if (status === "cleaned")
|
|
1926
|
+
else if (status === "cleaned")
|
|
1927
|
+
settingsMessages.push("ai-ops \uD0A4 \uC81C\uAC70 (\uC0AC\uC6A9\uC790 \uC124\uC815 \uBCF4\uC874): .claude/settings.local.json");
|
|
1947
1928
|
}
|
|
1948
1929
|
if (manifest.settings?.gemini) {
|
|
1949
1930
|
const status = uninstallGeminiSettings(basePath, manifest.settings.gemini);
|
|
@@ -1957,46 +1938,48 @@ ${targetSkillDirs.map((f) => ` ${f}`).join("\n")}`);
|
|
|
1957
1938
|
const removedSkillDirs = removeDirectories(basePath, targetSkillDirs);
|
|
1958
1939
|
const dirs = collectManagedDirs(targetFiles);
|
|
1959
1940
|
const removedDirs = cleanEmptyDirs(basePath, dirs);
|
|
1960
|
-
|
|
1941
|
+
rmSync5(manifestPath, { force: true });
|
|
1961
1942
|
if (result.deleted.length > 0) {
|
|
1962
|
-
|
|
1943
|
+
p6.log.success(`\uC0AD\uC81C \uC644\uB8CC (${result.deleted.length}\uAC1C):
|
|
1963
1944
|
${result.deleted.map((f) => ` ${f}`).join("\n")}`);
|
|
1964
1945
|
}
|
|
1965
1946
|
if (result.cleaned.length > 0) {
|
|
1966
|
-
|
|
1947
|
+
p6.log.success(
|
|
1967
1948
|
`\uC139\uC158 \uC81C\uAC70 \uC644\uB8CC (\uC0AC\uC6A9\uC790 \uB0B4\uC6A9 \uBCF4\uC874, ${result.cleaned.length}\uAC1C):
|
|
1968
1949
|
${result.cleaned.map((f) => ` ${f}`).join("\n")}`
|
|
1969
1950
|
);
|
|
1970
1951
|
}
|
|
1971
1952
|
if (result.skipped.length > 0) {
|
|
1972
|
-
|
|
1953
|
+
p6.log.warn(
|
|
1973
1954
|
`\uAC74\uB108\uB700 (non-managed \uD30C\uC77C \uBCF4\uD638, ${result.skipped.length}\uAC1C):
|
|
1974
1955
|
${result.skipped.map((f) => ` ${f}`).join("\n")}`
|
|
1975
1956
|
);
|
|
1976
1957
|
}
|
|
1977
1958
|
if (result.notFound.length > 0) {
|
|
1978
|
-
|
|
1959
|
+
p6.log.info(`\uC774\uBBF8 \uC5C6\uC74C (${result.notFound.length}\uAC1C):
|
|
1979
1960
|
${result.notFound.map((f) => ` ${f}`).join("\n")}`);
|
|
1980
1961
|
}
|
|
1981
1962
|
if (removedDirs.length > 0) {
|
|
1982
|
-
|
|
1963
|
+
p6.log.info(`\uBE48 \uB514\uB809\uD1A0\uB9AC \uC815\uB9AC (${removedDirs.length}\uAC1C):
|
|
1983
1964
|
${removedDirs.map((d) => ` ${d}`).join("\n")}`);
|
|
1984
1965
|
}
|
|
1985
1966
|
if (removedSkillDirs.length > 0) {
|
|
1986
|
-
|
|
1987
|
-
${removedSkillDirs.
|
|
1967
|
+
p6.log.success(
|
|
1968
|
+
`skill \uB514\uB809\uD1A0\uB9AC \uC0AD\uC81C (${removedSkillDirs.length}\uAC1C):
|
|
1969
|
+
${removedSkillDirs.map((d) => ` ${d}`).join("\n")}`
|
|
1970
|
+
);
|
|
1988
1971
|
}
|
|
1989
1972
|
if (settingsMessages.length > 0) {
|
|
1990
|
-
|
|
1973
|
+
p6.log.success(`\uC124\uC815 \uD30C\uC77C \uCC98\uB9AC:
|
|
1991
1974
|
${settingsMessages.map((m) => ` ${m}`).join("\n")}`);
|
|
1992
1975
|
}
|
|
1993
|
-
|
|
1994
|
-
|
|
1976
|
+
p6.log.success(`manifest \uC0AD\uC81C: ${MANIFEST_FILENAME}`);
|
|
1977
|
+
p6.outro("ai-ops uninstall \uC644\uB8CC");
|
|
1995
1978
|
};
|
|
1996
1979
|
|
|
1997
1980
|
// src/commands/skill.ts
|
|
1998
|
-
import * as
|
|
1999
|
-
import { rmSync as
|
|
1981
|
+
import * as p7 from "@clack/prompts";
|
|
1982
|
+
import { rmSync as rmSync6 } from "fs";
|
|
2000
1983
|
var resolveScopeContext = (opts) => {
|
|
2001
1984
|
const scope = resolveSkillScope(opts);
|
|
2002
1985
|
return {
|
|
@@ -2032,7 +2015,7 @@ var writeProjectSkillState = (params) => {
|
|
|
2032
2015
|
const nextTools = params.nextSkill !== void 0 ? [.../* @__PURE__ */ new Set([...previous?.tools ?? [], ...params.nextSkill.tools])] : previous?.tools ?? [];
|
|
2033
2016
|
const hasProjectState = (previous?.installed_rules.length ?? 0) > 0 || (previous?.installed_files?.length ?? 0) > 0 || (previous?.appended_files?.length ?? 0) > 0 || installedSkills.length > 0 || previous?.settings !== void 0;
|
|
2034
2017
|
if (!hasProjectState) {
|
|
2035
|
-
|
|
2018
|
+
rmSync6(manifestPath, { force: true });
|
|
2036
2019
|
return;
|
|
2037
2020
|
}
|
|
2038
2021
|
const manifest = buildManifest({
|
|
@@ -2055,7 +2038,7 @@ var writeUserSkillState = (params) => {
|
|
|
2055
2038
|
const previous = readSkillRegistry(registryPath);
|
|
2056
2039
|
const skills = params.removeSkillId ? removeInstalledSkill(previous?.skills ?? [], params.removeSkillId) : params.nextSkill ? upsertInstalledSkill(previous?.skills ?? [], params.nextSkill) : previous?.skills ?? [];
|
|
2057
2040
|
if (skills.length === 0) {
|
|
2058
|
-
|
|
2041
|
+
rmSync6(registryPath, { force: true });
|
|
2059
2042
|
return;
|
|
2060
2043
|
}
|
|
2061
2044
|
writeSkillRegistry(registryPath, {
|
|
@@ -2109,7 +2092,7 @@ var skillListCommand = async (opts) => {
|
|
|
2109
2092
|
const { scope, basePath } = resolveScopeContext(opts);
|
|
2110
2093
|
const { allSkills } = loadCompilerInputs();
|
|
2111
2094
|
const installedSkills = readInstalledSkills(scope, basePath);
|
|
2112
|
-
|
|
2095
|
+
p7.intro(`ai-ops skill list (${scope})`);
|
|
2113
2096
|
const sections = [
|
|
2114
2097
|
{ kind: "reference", title: "reference skills" },
|
|
2115
2098
|
{ kind: "task", title: "task skills" }
|
|
@@ -2125,8 +2108,8 @@ var skillListCommand = async (opts) => {
|
|
|
2125
2108
|
return `${title}
|
|
2126
2109
|
${lines.join("\n")}`;
|
|
2127
2110
|
}).filter((section) => section !== null);
|
|
2128
|
-
|
|
2129
|
-
|
|
2111
|
+
p7.log.info(sections.join("\n\n"));
|
|
2112
|
+
p7.outro("ai-ops skill list \uC644\uB8CC");
|
|
2130
2113
|
};
|
|
2131
2114
|
var skillInstallCommand = async (skillId, opts) => {
|
|
2132
2115
|
const { scope, basePath } = resolveScopeContext(opts);
|
|
@@ -2134,7 +2117,7 @@ var skillInstallCommand = async (skillId, opts) => {
|
|
|
2134
2117
|
const skill = resolveSkillById(allSkills, skillId);
|
|
2135
2118
|
assertScopeAllowed(skill, scope);
|
|
2136
2119
|
const requestedTools = resolveRequestedTools({ requested: opts.tool, supported: skill.supported_tools });
|
|
2137
|
-
|
|
2120
|
+
p7.intro(`ai-ops skill install ${skillId}`);
|
|
2138
2121
|
const installedSkill = installSkill({
|
|
2139
2122
|
skill,
|
|
2140
2123
|
requestedTools,
|
|
@@ -2143,18 +2126,18 @@ var skillInstallCommand = async (skillId, opts) => {
|
|
|
2143
2126
|
cliVersion,
|
|
2144
2127
|
sourceHash
|
|
2145
2128
|
});
|
|
2146
|
-
|
|
2147
|
-
|
|
2129
|
+
p7.log.success(`\uC124\uCE58 \uC644\uB8CC: ${installedSkill.id} (${installedSkill.installed_paths.join(", ")})`);
|
|
2130
|
+
p7.outro("ai-ops skill install \uC644\uB8CC");
|
|
2148
2131
|
};
|
|
2149
2132
|
var skillDiffCommand = async (skillId, opts) => {
|
|
2150
2133
|
const { scope, basePath } = resolveScopeContext(opts);
|
|
2151
2134
|
const { allSkills } = loadCompilerInputs();
|
|
2152
2135
|
const installedSkills = readInstalledSkills(scope, basePath);
|
|
2153
2136
|
const targets = skillId ? installedSkills.filter((skill) => skill.id === skillId) : installedSkills;
|
|
2154
|
-
|
|
2137
|
+
p7.intro(`ai-ops skill diff (${scope})`);
|
|
2155
2138
|
if (targets.length === 0) {
|
|
2156
|
-
|
|
2157
|
-
|
|
2139
|
+
p7.log.warn("\uBE44\uAD50\uD560 \uC124\uCE58\uB41C skill\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
2140
|
+
p7.outro("ai-ops skill diff \uC644\uB8CC");
|
|
2158
2141
|
return;
|
|
2159
2142
|
}
|
|
2160
2143
|
const lines = targets.map((installedSkill) => {
|
|
@@ -2167,18 +2150,18 @@ var skillDiffCommand = async (skillId, opts) => {
|
|
|
2167
2150
|
const changed = next.sourceHash !== installedSkill.sourceHash;
|
|
2168
2151
|
return `- ${installedSkill.id}: ${changed ? "changed" : "up-to-date"} (${installedSkill.sourceHash} -> ${next.sourceHash})`;
|
|
2169
2152
|
});
|
|
2170
|
-
|
|
2171
|
-
|
|
2153
|
+
p7.log.info(lines.join("\n"));
|
|
2154
|
+
p7.outro("ai-ops skill diff \uC644\uB8CC");
|
|
2172
2155
|
};
|
|
2173
2156
|
var skillUpdateCommand = async (skillId, opts) => {
|
|
2174
2157
|
const { scope, basePath } = resolveScopeContext(opts);
|
|
2175
2158
|
const { allSkills, sourceHash, cliVersion } = loadCompilerInputs();
|
|
2176
2159
|
const installedSkills = readInstalledSkills(scope, basePath);
|
|
2177
2160
|
const targets = skillId ? installedSkills.filter((skill) => skill.id === skillId) : installedSkills;
|
|
2178
|
-
|
|
2161
|
+
p7.intro(`ai-ops skill update (${scope})`);
|
|
2179
2162
|
if (targets.length === 0) {
|
|
2180
|
-
|
|
2181
|
-
|
|
2163
|
+
p7.log.warn("\uAC31\uC2E0\uD560 \uC124\uCE58\uB41C skill\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
2164
|
+
p7.outro("ai-ops skill update \uC644\uB8CC");
|
|
2182
2165
|
return;
|
|
2183
2166
|
}
|
|
2184
2167
|
const nextInstalledSkills = targets.map((installedSkill) => {
|
|
@@ -2195,7 +2178,7 @@ var skillUpdateCommand = async (skillId, opts) => {
|
|
|
2195
2178
|
const manifestPath = resolveManifestPath(basePath);
|
|
2196
2179
|
const previous = readManifest(manifestPath);
|
|
2197
2180
|
if (!previous) {
|
|
2198
|
-
|
|
2181
|
+
p7.log.error("project manifest\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
2199
2182
|
process.exit(1);
|
|
2200
2183
|
}
|
|
2201
2184
|
const untouched = (previous.installed_skills ?? []).filter(
|
|
@@ -2229,18 +2212,18 @@ var skillUpdateCommand = async (skillId, opts) => {
|
|
|
2229
2212
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2230
2213
|
});
|
|
2231
2214
|
}
|
|
2232
|
-
|
|
2233
|
-
|
|
2215
|
+
p7.log.success(`\uAC31\uC2E0 \uC644\uB8CC: ${nextInstalledSkills.map((skill) => skill.id).join(", ")}`);
|
|
2216
|
+
p7.outro("ai-ops skill update \uC644\uB8CC");
|
|
2234
2217
|
};
|
|
2235
2218
|
var skillUninstallCommand = async (skillId, opts) => {
|
|
2236
2219
|
const { scope, basePath } = resolveScopeContext(opts);
|
|
2237
2220
|
const { sourceHash, cliVersion } = loadCompilerInputs();
|
|
2238
2221
|
const installedSkills = readInstalledSkills(scope, basePath);
|
|
2239
2222
|
const installedSkill = findInstalledSkill(installedSkills, skillId);
|
|
2240
|
-
|
|
2223
|
+
p7.intro(`ai-ops skill uninstall ${skillId}`);
|
|
2241
2224
|
if (!installedSkill) {
|
|
2242
|
-
|
|
2243
|
-
|
|
2225
|
+
p7.log.warn("\uC124\uCE58\uB41C skill\uC744 \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
|
|
2226
|
+
p7.outro("ai-ops skill uninstall \uC644\uB8CC");
|
|
2244
2227
|
return;
|
|
2245
2228
|
}
|
|
2246
2229
|
const removed = removeDirectories(basePath, installedSkill.installed_paths);
|
|
@@ -2258,8 +2241,29 @@ var skillUninstallCommand = async (skillId, opts) => {
|
|
|
2258
2241
|
removeSkillId: skillId
|
|
2259
2242
|
});
|
|
2260
2243
|
}
|
|
2261
|
-
|
|
2262
|
-
|
|
2244
|
+
p7.log.success(`\uC81C\uAC70 \uC644\uB8CC: ${removed.join(", ")}`);
|
|
2245
|
+
p7.outro("ai-ops skill uninstall \uC644\uB8CC");
|
|
2246
|
+
};
|
|
2247
|
+
|
|
2248
|
+
// src/commands/spec.ts
|
|
2249
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync6, writeFileSync as writeFileSync8 } from "fs";
|
|
2250
|
+
import { join as join13, dirname as dirname8 } from "path";
|
|
2251
|
+
import * as p8 from "@clack/prompts";
|
|
2252
|
+
var specInitCommand = async (opts) => {
|
|
2253
|
+
p8.intro("ai-ops spec init");
|
|
2254
|
+
const specsDir = join13(process.cwd(), "specs");
|
|
2255
|
+
if (existsSync8(specsDir) && !opts.force) {
|
|
2256
|
+
p8.log.error("specs/ \uB514\uB809\uD1A0\uB9AC\uAC00 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4. \uB36E\uC5B4\uC4F0\uB824\uBA74 --force \uC635\uC158\uC744 \uC0AC\uC6A9\uD558\uC138\uC694.");
|
|
2257
|
+
process.exit(1);
|
|
2258
|
+
}
|
|
2259
|
+
const actions = buildSpecInitPlan();
|
|
2260
|
+
for (const action of actions) {
|
|
2261
|
+
const dest = join13(process.cwd(), action.relativePath);
|
|
2262
|
+
mkdirSync6(dirname8(dest), { recursive: true });
|
|
2263
|
+
writeFileSync8(dest, action.content, "utf-8");
|
|
2264
|
+
p8.log.success(`\uC0DD\uC131: ${action.relativePath}`);
|
|
2265
|
+
}
|
|
2266
|
+
p8.outro("ai-ops spec init \uC644\uB8CC");
|
|
2263
2267
|
};
|
|
2264
2268
|
|
|
2265
2269
|
// src/bin/index.ts
|
|
@@ -2286,5 +2290,7 @@ applySkillScopeOptions(skillCommand.command("update [skillId]").description("ski
|
|
|
2286
2290
|
applySkillScopeOptions(skillCommand.command("uninstall <skillId>").description("skill \uC81C\uAC70")).action(
|
|
2287
2291
|
(skillId, opts) => skillUninstallCommand(skillId, opts)
|
|
2288
2292
|
);
|
|
2293
|
+
var specCommand = program.command("spec").description("spec \uD30C\uC774\uD504\uB77C\uC778 \uAD00\uB9AC");
|
|
2294
|
+
specCommand.command("init").description("specs/ \uB514\uB809\uD1A0\uB9AC \uAD6C\uC870 \uCD08\uAE30\uD654").option("--force", "\uC774\uBBF8 \uC874\uC7AC\uD574\uB3C4 \uAC15\uC81C \uC7AC\uC0DD\uC131", false).action((opts) => specInitCommand(opts));
|
|
2289
2295
|
program.parse();
|
|
2290
2296
|
//# sourceMappingURL=index.js.map
|