ethan-skill 1.5.4 → 1.5.6
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/cli/index.js +114 -57
- package/dist/cli/index.js.map +1 -1
- package/dist/server/dashboard.d.ts.map +1 -1
- package/dist/server/dashboard.js +7 -12
- package/dist/server/dashboard.js.map +1 -1
- package/dist/workflow/state.d.ts +8 -2
- package/dist/workflow/state.d.ts.map +1 -1
- package/dist/workflow/state.js +36 -4
- package/dist/workflow/state.js.map +1 -1
- package/package.json +1 -1
- package/rules/claude-code/CLAUDE.md +51 -2
- package/rules/cline/.clinerules +51 -2
- package/rules/codebuddy/CODEBUDDY.md +51 -2
- package/rules/continue/.continuerules +2 -2
- package/rules/copilot/copilot-instructions.md +51 -2
- package/rules/cursor/.cursorrules +2 -2
- package/rules/cursor/smart-flow.mdc +2 -2
- package/rules/jetbrains/smart-flow.md +51 -2
- package/rules/lingma/smart-flow.md +51 -2
- package/rules/windsurf/.windsurf/rules/smart-flow.md +51 -2
- package/rules/zed/smart-flow.rules +52 -1
package/dist/cli/index.js
CHANGED
|
@@ -910,7 +910,7 @@ program
|
|
|
910
910
|
const workflowCmd = program.command('workflow').description('有状态工作流执行:一键推进各阶段任务');
|
|
911
911
|
workflowCmd
|
|
912
912
|
.command('start [pipelineId]')
|
|
913
|
-
.description('
|
|
913
|
+
.description('启动工作流会话,输出第一步提示词(无参数时显示 Pipeline 选择菜单)')
|
|
914
914
|
.option('-c, --context <context>', '初始任务上下文', '')
|
|
915
915
|
.option('-n, --name <name>', '具名会话(存至 .ethan/sessions/<name>.json,可并行多个工作流)')
|
|
916
916
|
.action(async (pipelineId, options) => {
|
|
@@ -928,7 +928,39 @@ workflowCmd
|
|
|
928
928
|
console.log(' 使用 ethan workflow reset 重置后再启动新工作流\n');
|
|
929
929
|
return;
|
|
930
930
|
}
|
|
931
|
-
|
|
931
|
+
let id = pipelineId;
|
|
932
|
+
// 无参数时,显示交互式 Pipeline 选择菜单
|
|
933
|
+
if (!id) {
|
|
934
|
+
const customPipelines = loadCustomPipelines(process.cwd());
|
|
935
|
+
const allPipelines = [
|
|
936
|
+
...PIPELINES,
|
|
937
|
+
...customPipelines.map((p) => ({ id: p.id, name: p.name, description: p.description, skillIds: p.skillIds })),
|
|
938
|
+
];
|
|
939
|
+
const readline = await Promise.resolve().then(() => __importStar(require('readline')));
|
|
940
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
941
|
+
const ask = (q) => new Promise((resolve) => rl.question(q, (a) => resolve(a.trim())));
|
|
942
|
+
console.log('\n🔄 可用工作流 Pipeline\n');
|
|
943
|
+
console.log('─'.repeat(60));
|
|
944
|
+
allPipelines.forEach((p, i) => {
|
|
945
|
+
console.log(` ${i + 1}. ${p.name} [${p.id}]`);
|
|
946
|
+
console.log(` ${p.description}`);
|
|
947
|
+
console.log(` 步骤: ${p.skillIds.join(' → ')}`);
|
|
948
|
+
console.log('');
|
|
949
|
+
});
|
|
950
|
+
const choice = await ask(`选择 Pipeline(输入序号 1-${allPipelines.length},或直接输入 ID):\n> `);
|
|
951
|
+
rl.close();
|
|
952
|
+
if (!choice) {
|
|
953
|
+
console.error('\n❌ 未选择 Pipeline\n');
|
|
954
|
+
process.exit(1);
|
|
955
|
+
}
|
|
956
|
+
const num = parseInt(choice, 10);
|
|
957
|
+
if (!isNaN(num) && num >= 1 && num <= allPipelines.length) {
|
|
958
|
+
id = allPipelines[num - 1].id;
|
|
959
|
+
}
|
|
960
|
+
else {
|
|
961
|
+
id = choice;
|
|
962
|
+
}
|
|
963
|
+
}
|
|
932
964
|
let resolved = resolvePipeline(id);
|
|
933
965
|
// 尝试从自定义 YAML pipeline 加载
|
|
934
966
|
if (!resolved) {
|
|
@@ -990,15 +1022,56 @@ workflowCmd
|
|
|
990
1022
|
if (copyToClipboard(prompt)) {
|
|
991
1023
|
console.log('\n✅ 提示词已复制到剪贴板!粘贴到你的 AI 编辑器中执行。');
|
|
992
1024
|
}
|
|
993
|
-
console.log(`\n💡 完成本步后,运行:ethan workflow done
|
|
1025
|
+
console.log(`\n💡 完成本步后,运行:ethan workflow done${session.name ? ` --name ${session.name}` : ''}\n`);
|
|
994
1026
|
// 记录使用统计
|
|
995
1027
|
const stats = readStats();
|
|
996
1028
|
stats[firstSkill.id] = (stats[firstSkill.id] || 0) + 1;
|
|
997
1029
|
writeStats(stats);
|
|
998
1030
|
});
|
|
1031
|
+
workflowCmd
|
|
1032
|
+
.command('use [name]')
|
|
1033
|
+
.description('设置当前工作目录的活跃会话(后续命令无需 --name);不传 name 则显示当前激活会话')
|
|
1034
|
+
.action(async (name) => {
|
|
1035
|
+
const { getCurrentSessionName, setCurrentSessionName, clearCurrentSessionName, loadSession } = await Promise.resolve().then(() => __importStar(require('../workflow/state')));
|
|
1036
|
+
if (!name) {
|
|
1037
|
+
const current = getCurrentSessionName(process.cwd());
|
|
1038
|
+
if (!current) {
|
|
1039
|
+
console.log('\n📌 当前无激活会话(使用默认 workflow.json)');
|
|
1040
|
+
console.log(' 运行 ethan workflow use <name> 激活一个具名会话\n');
|
|
1041
|
+
}
|
|
1042
|
+
else {
|
|
1043
|
+
const session = loadSession(process.cwd(), current);
|
|
1044
|
+
console.log(`\n📌 当前激活会话:${current}`);
|
|
1045
|
+
if (session) {
|
|
1046
|
+
const { calcProgress } = await Promise.resolve().then(() => __importStar(require('../workflow/state')));
|
|
1047
|
+
console.log(` Pipeline: ${session.pipelineName}`);
|
|
1048
|
+
console.log(` 进度: ${calcProgress(session)}%`);
|
|
1049
|
+
}
|
|
1050
|
+
console.log('\n 运行 ethan workflow use (不带参数)可查看,ethan workflow use default 可切回默认\n');
|
|
1051
|
+
}
|
|
1052
|
+
return;
|
|
1053
|
+
}
|
|
1054
|
+
if (name === 'default' || name === '-') {
|
|
1055
|
+
clearCurrentSessionName(process.cwd());
|
|
1056
|
+
console.log('\n✅ 已切换回默认会话(workflow.json)\n');
|
|
1057
|
+
return;
|
|
1058
|
+
}
|
|
1059
|
+
const session = loadSession(process.cwd(), name);
|
|
1060
|
+
if (!session) {
|
|
1061
|
+
console.error(`\n❌ 未找到具名会话:${name}`);
|
|
1062
|
+
console.error(' 使用 ethan workflow list 查看所有会话\n');
|
|
1063
|
+
process.exit(1);
|
|
1064
|
+
}
|
|
1065
|
+
setCurrentSessionName(process.cwd(), name);
|
|
1066
|
+
const { calcProgress } = await Promise.resolve().then(() => __importStar(require('../workflow/state')));
|
|
1067
|
+
console.log(`\n✅ 已激活会话:${name}`);
|
|
1068
|
+
console.log(` Pipeline: ${session.pipelineName}`);
|
|
1069
|
+
console.log(` 进度: ${calcProgress(session)}%`);
|
|
1070
|
+
console.log('\n 后续 workflow done/status/reset 将自动使用此会话(无需 --name)\n');
|
|
1071
|
+
});
|
|
999
1072
|
workflowCmd
|
|
1000
1073
|
.command('done [summary]')
|
|
1001
|
-
.description('
|
|
1074
|
+
.description('完成当前步骤,自动推进到下一步(摘要可选)')
|
|
1002
1075
|
.option('-n, --name <name>', '具名会话名称')
|
|
1003
1076
|
.action(async (summary, options) => {
|
|
1004
1077
|
const { loadSession, markStepDone, buildStepPrompt, getCurrentStep, getCurrentStepIndex, calcProgress, } = await Promise.resolve().then(() => __importStar(require('../workflow/state')));
|
|
@@ -1017,21 +1090,8 @@ workflowCmd
|
|
|
1017
1090
|
console.error('\n❌ 未找到当前步骤,工作流状态异常。\n');
|
|
1018
1091
|
process.exit(1);
|
|
1019
1092
|
}
|
|
1020
|
-
//
|
|
1021
|
-
|
|
1022
|
-
if (!stepSummary) {
|
|
1023
|
-
const readline = await Promise.resolve().then(() => __importStar(require('readline')));
|
|
1024
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
1025
|
-
const ask = (q) => new Promise((resolve) => rl.question(q, (a) => resolve(a.trim())));
|
|
1026
|
-
const currentIdx = getCurrentStepIndex(session);
|
|
1027
|
-
console.log(`\n✅ 完成第 ${currentIdx + 1} 步:${currentStep.skillId}`);
|
|
1028
|
-
stepSummary = await ask('请输入本步执行摘要(将作为下一步的上下文):\n> ');
|
|
1029
|
-
rl.close();
|
|
1030
|
-
if (!stepSummary) {
|
|
1031
|
-
console.error('\n❌ 摘要不能为空\n');
|
|
1032
|
-
process.exit(1);
|
|
1033
|
-
}
|
|
1034
|
-
}
|
|
1093
|
+
// 获取摘要(命令行参数,可选)
|
|
1094
|
+
const stepSummary = summary?.trim() ?? '';
|
|
1035
1095
|
const nextStep = markStepDone(session, stepSummary, process.cwd());
|
|
1036
1096
|
const progress = calcProgress(session);
|
|
1037
1097
|
// 自动归档到 Skill Memory(T16)
|
|
@@ -1064,7 +1124,7 @@ workflowCmd
|
|
|
1064
1124
|
if (copyToClipboard(prompt)) {
|
|
1065
1125
|
console.log('\n✅ 下一步提示词已复制到剪贴板!');
|
|
1066
1126
|
}
|
|
1067
|
-
console.log(`\n💡 完成本步后,运行:ethan workflow done
|
|
1127
|
+
console.log(`\n💡 完成本步后,运行:ethan workflow done${session.name ? ` --name ${session.name}` : ''}\n`);
|
|
1068
1128
|
// 记录使用统计
|
|
1069
1129
|
const stats = readStats();
|
|
1070
1130
|
stats[nextSkill.id] = (stats[nextSkill.id] || 0) + 1;
|
|
@@ -1121,7 +1181,7 @@ workflowCmd
|
|
|
1121
1181
|
}
|
|
1122
1182
|
else {
|
|
1123
1183
|
console.log(`\n💡 当前任务背景:${session.initialContext}`);
|
|
1124
|
-
console.log(` 完成当前步骤后运行:ethan workflow done
|
|
1184
|
+
console.log(` 完成当前步骤后运行:ethan workflow done${session.name ? ` --name ${session.name}` : ''}\n`);
|
|
1125
1185
|
}
|
|
1126
1186
|
});
|
|
1127
1187
|
workflowCmd
|
|
@@ -1152,47 +1212,44 @@ workflowCmd
|
|
|
1152
1212
|
});
|
|
1153
1213
|
workflowCmd
|
|
1154
1214
|
.command('list')
|
|
1155
|
-
.description('
|
|
1156
|
-
.
|
|
1157
|
-
.
|
|
1158
|
-
const
|
|
1159
|
-
const
|
|
1160
|
-
// ── 列出具名会话 ─────────────────────────────────────────────────────────
|
|
1215
|
+
.description('列出所有进行中的会话(具名 + 默认)')
|
|
1216
|
+
.action(async () => {
|
|
1217
|
+
const { loadSession, calcProgress, listNamedSessions, getCurrentSessionName } = await Promise.resolve().then(() => __importStar(require('../workflow/state')));
|
|
1218
|
+
const currentActiveName = getCurrentSessionName(process.cwd());
|
|
1219
|
+
const defaultSession = loadSession(process.cwd(), undefined);
|
|
1161
1220
|
const namedSessions = listNamedSessions(process.cwd());
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
}
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1221
|
+
console.log('\n📂 工作流会话\n');
|
|
1222
|
+
console.log('─'.repeat(60));
|
|
1223
|
+
// 默认会话
|
|
1224
|
+
if (defaultSession) {
|
|
1225
|
+
const pct = calcProgress(defaultSession);
|
|
1226
|
+
const statusLabel = defaultSession.completed ? '🎉 已完成' : `${pct}% 进行中`;
|
|
1227
|
+
const activeTag = !currentActiveName ? ' ◀ 当前激活' : '';
|
|
1228
|
+
console.log(`\n 📋 默认会话${activeTag} [${statusLabel}]`);
|
|
1229
|
+
console.log(` Pipeline: ${defaultSession.pipelineName}`);
|
|
1230
|
+
console.log(` 背景: ${defaultSession.initialContext.slice(0, 60)}${defaultSession.initialContext.length > 60 ? '…' : ''}`);
|
|
1231
|
+
console.log(` 更新: ${defaultSession.updatedAt.slice(0, 19).replace('T', ' ')}`);
|
|
1232
|
+
}
|
|
1233
|
+
// 具名会话
|
|
1234
|
+
if (namedSessions.length > 0) {
|
|
1235
|
+
for (const s of namedSessions) {
|
|
1236
|
+
const pct = calcProgress(s);
|
|
1237
|
+
const statusLabel = s.completed ? '🎉 已完成' : `${pct}% 进行中`;
|
|
1238
|
+
const isActive = s.name === currentActiveName;
|
|
1239
|
+
const activeTag = isActive ? ' ◀ 当前激活' : '';
|
|
1240
|
+
console.log(`\n 📌 ${s.name || s.id}${activeTag} [${statusLabel}]`);
|
|
1241
|
+
console.log(` Pipeline: ${s.pipelineName}`);
|
|
1242
|
+
console.log(` 背景: ${s.initialContext.slice(0, 60)}${s.initialContext.length > 60 ? '…' : ''}`);
|
|
1243
|
+
console.log(` 更新: ${s.updatedAt.slice(0, 19).replace('T', ' ')}`);
|
|
1177
1244
|
}
|
|
1178
|
-
console.log('\n' + '─'.repeat(60));
|
|
1179
|
-
if (options.sessions)
|
|
1180
|
-
return;
|
|
1181
1245
|
}
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
console.log('─'.repeat(60));
|
|
1185
|
-
for (const p of PIPELINES) {
|
|
1186
|
-
const isCurrent = current?.pipelineId === p.id && !current.completed;
|
|
1187
|
-
const tag = isCurrent ? ` ◀ 进行中(${calcProgress(current)}%)` : '';
|
|
1188
|
-
console.log(`\n ${p.id}${tag}`);
|
|
1189
|
-
console.log(` 名称:${p.name}`);
|
|
1190
|
-
console.log(` 描述:${p.description}`);
|
|
1191
|
-
console.log(` 步骤:${p.skillIds.join(' → ')}`);
|
|
1246
|
+
if (!defaultSession && namedSessions.length === 0) {
|
|
1247
|
+
console.log(' 暂无工作流会话。');
|
|
1192
1248
|
}
|
|
1193
1249
|
console.log('\n' + '─'.repeat(60));
|
|
1194
|
-
console.log('\n启动工作流:ethan workflow start
|
|
1195
|
-
console.log('
|
|
1250
|
+
console.log('\n💡 启动工作流:ethan workflow start');
|
|
1251
|
+
console.log(' 激活会话: ethan workflow use <session-name>');
|
|
1252
|
+
console.log(' 查看 Pipeline:ethan pipeline list\n');
|
|
1196
1253
|
});
|
|
1197
1254
|
workflowCmd
|
|
1198
1255
|
.command('report')
|