dflow-sdd-ddd 0.4.0 → 0.5.0
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/CHANGELOG.md +26 -0
- package/README.en.md +2 -4
- package/README.md +2 -4
- package/TEMPLATE-COVERAGE.md +1 -1
- package/bin/dflow.js +11 -5
- package/docs/evaluating-dflow.en.md +2 -5
- package/docs/evaluating-dflow.md +1 -3
- package/docs/migrating-to-dflow-v1.md +1 -1
- package/docs/using-with-claude-code.en.md +38 -8
- package/docs/using-with-claude-code.md +33 -7
- package/docs/using-with-codex.en.md +31 -5
- package/docs/using-with-codex.md +28 -5
- package/docs/using-with-github-copilot.en.md +29 -5
- package/docs/using-with-github-copilot.md +28 -5
- package/lib/init.js +250 -22
- package/package.json +1 -1
- package/templates/brownfield/scaffolding/AI-AGENT-GUIDE.md +42 -3
- package/templates/greenfield/scaffolding/AI-AGENT-GUIDE.md +42 -3
- package/templates/greenfield/scaffolding/CLAUDE-md-snippet.md +1 -0
- package/docs/using-with-gemini-cli.en.md +0 -200
- package/docs/using-with-gemini-cli.md +0 -184
package/lib/init.js
CHANGED
|
@@ -8,6 +8,21 @@ const pkg = require('../package.json');
|
|
|
8
8
|
const MIN_NODE_VERSION = '22.0.0';
|
|
9
9
|
const PACKAGE_ROOT = path.resolve(__dirname, '..');
|
|
10
10
|
const TEMPLATE_ROOT = path.join(PACKAGE_ROOT, 'templates');
|
|
11
|
+
const COMMAND_REGISTRY_START = '<!-- dflow-command-registry:start -->';
|
|
12
|
+
const COMMAND_REGISTRY_END = '<!-- dflow-command-registry:end -->';
|
|
13
|
+
const EXPECTED_COMMAND_IDS = [
|
|
14
|
+
'new-feature',
|
|
15
|
+
'modify-existing',
|
|
16
|
+
'bug-fix',
|
|
17
|
+
'new-phase',
|
|
18
|
+
'finish-feature',
|
|
19
|
+
'verify',
|
|
20
|
+
'pr-review',
|
|
21
|
+
'report-dflow-feedback',
|
|
22
|
+
'status',
|
|
23
|
+
'next',
|
|
24
|
+
'cancel'
|
|
25
|
+
];
|
|
11
26
|
|
|
12
27
|
const PROSE_LANGUAGE_PATTERN =
|
|
13
28
|
/^[A-Za-z]{2,3}(?:-[A-Za-z]{4})?(?:-(?:[A-Za-z]{2}|[0-9]{3}))?(?:-(?:[A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3}))*$/;
|
|
@@ -91,11 +106,6 @@ const AI_AGENT_OPTIONS = [
|
|
|
91
106
|
label: 'CLAUDE.md - Claude Code',
|
|
92
107
|
aliases: ['claude', 'claude.md']
|
|
93
108
|
},
|
|
94
|
-
{
|
|
95
|
-
key: 'gemini',
|
|
96
|
-
label: 'GEMINI.md - Gemini CLI',
|
|
97
|
-
aliases: ['gemini', 'gemini.md']
|
|
98
|
-
},
|
|
99
109
|
{
|
|
100
110
|
key: 'copilot',
|
|
101
111
|
label: '.github/copilot-instructions.md - GitHub Copilot',
|
|
@@ -251,7 +261,8 @@ async function runConfigureAgents(options = {}) {
|
|
|
251
261
|
|
|
252
262
|
const plan = await buildConfigureAgentsPlan(cwd, {
|
|
253
263
|
...projectContext,
|
|
254
|
-
aiAgents
|
|
264
|
+
aiAgents,
|
|
265
|
+
commandAdapters: Boolean(options.commandAdapters)
|
|
255
266
|
});
|
|
256
267
|
|
|
257
268
|
renderPreview(stdout, plan, []);
|
|
@@ -268,7 +279,7 @@ async function runConfigureAgents(options = {}) {
|
|
|
268
279
|
result.warnings.push(...collectUnresolvedPlaceholderWarnings(plan, result.created));
|
|
269
280
|
|
|
270
281
|
printResultReport(stdout, result, plan.deferred);
|
|
271
|
-
printConfigureAgentsNextSteps(stdout);
|
|
282
|
+
printConfigureAgentsNextSteps(stdout, Boolean(options.commandAdapters));
|
|
272
283
|
return 0;
|
|
273
284
|
} catch (error) {
|
|
274
285
|
if (rl) {
|
|
@@ -999,8 +1010,14 @@ async function buildConfigureAgentsPlan(cwd, answers) {
|
|
|
999
1010
|
content
|
|
1000
1011
|
});
|
|
1001
1012
|
|
|
1013
|
+
const commandRegistry = answers.commandAdapters ? parseDflowCommandRegistry(content) : [];
|
|
1014
|
+
|
|
1002
1015
|
for (const agent of answers.aiAgents) {
|
|
1003
|
-
await addAiAgentShim(cwd, items, agent, substitution);
|
|
1016
|
+
await addAiAgentShim(cwd, items, agent, substitution, { commandRegistry });
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
if (answers.commandAdapters) {
|
|
1020
|
+
addCommandAdapterItems(items, answers.aiAgents, commandRegistry);
|
|
1004
1021
|
}
|
|
1005
1022
|
|
|
1006
1023
|
await finalizePlanItems(cwd, items);
|
|
@@ -1017,7 +1034,8 @@ async function buildConfigureAgentsPlan(cwd, answers) {
|
|
|
1017
1034
|
async function finalizePlanItems(cwd, items) {
|
|
1018
1035
|
for (const item of items) {
|
|
1019
1036
|
const absolute = path.join(cwd, item.relativePath);
|
|
1020
|
-
|
|
1037
|
+
const targetExists = await pathExists(absolute);
|
|
1038
|
+
item.action = targetExists ? (item.overwrite ? 'update' : 'skip') : 'create';
|
|
1021
1039
|
if (item.action === 'skip') {
|
|
1022
1040
|
item.notes = item.notes ? `${item.notes}, already exists` : 'already exists';
|
|
1023
1041
|
}
|
|
@@ -1025,15 +1043,23 @@ async function finalizePlanItems(cwd, items) {
|
|
|
1025
1043
|
}
|
|
1026
1044
|
}
|
|
1027
1045
|
|
|
1028
|
-
async function addAiAgentShim(cwd, items, agent, substitution) {
|
|
1046
|
+
async function addAiAgentShim(cwd, items, agent, substitution, options = {}) {
|
|
1029
1047
|
const target = getAiAgentTarget(agent);
|
|
1030
1048
|
const targetPath = path.join(cwd, target.relativePath);
|
|
1031
1049
|
const targetExists = await pathExists(targetPath);
|
|
1032
1050
|
const targetConfigured = targetExists && await fileReferencesAiAgentGuide(targetPath);
|
|
1033
|
-
const
|
|
1034
|
-
const
|
|
1051
|
+
const commandRegistry = options.commandRegistry || [];
|
|
1052
|
+
const codexCommandAdapterSnippet = target.relativePath === 'AGENTS.md' && commandRegistry.length > 0 && targetExists;
|
|
1053
|
+
const relativePath = codexCommandAdapterSnippet
|
|
1054
|
+
? (targetConfigured ? 'dflow/specs/shared/AGENTS-md-command-adapters-snippet.md' : target.snippetPath)
|
|
1055
|
+
: (targetExists && !targetConfigured ? target.snippetPath : target.relativePath);
|
|
1056
|
+
const content = substitutePlaceholders(buildAiAgentShim(target.relativePath, options.commandRegistry), substitution);
|
|
1035
1057
|
let notes = 'selected, tool-specific shim';
|
|
1036
|
-
if (targetConfigured) {
|
|
1058
|
+
if (codexCommandAdapterSnippet && targetConfigured) {
|
|
1059
|
+
notes = `selected, ${target.relativePath} already points to AI-AGENT-GUIDE.md; merge this command trigger snippet manually`;
|
|
1060
|
+
} else if (codexCommandAdapterSnippet) {
|
|
1061
|
+
notes = `selected, ${target.relativePath} already exists; merge this command trigger snippet manually`;
|
|
1062
|
+
} else if (targetConfigured) {
|
|
1037
1063
|
notes = `selected, ${target.relativePath} already points to AI-AGENT-GUIDE.md`;
|
|
1038
1064
|
} else if (targetExists) {
|
|
1039
1065
|
notes = `selected, ${target.relativePath} already exists; merge this snippet manually`;
|
|
@@ -1043,7 +1069,8 @@ async function addAiAgentShim(cwd, items, agent, substitution) {
|
|
|
1043
1069
|
relativePath,
|
|
1044
1070
|
source: `generated:${agent}-shim`,
|
|
1045
1071
|
notes,
|
|
1046
|
-
content
|
|
1072
|
+
content,
|
|
1073
|
+
overwrite: codexCommandAdapterSnippet
|
|
1047
1074
|
});
|
|
1048
1075
|
}
|
|
1049
1076
|
|
|
@@ -1067,10 +1094,6 @@ function getAiAgentTarget(agent) {
|
|
|
1067
1094
|
relativePath: 'CLAUDE.md',
|
|
1068
1095
|
snippetPath: 'dflow/specs/shared/CLAUDE-md-snippet.md'
|
|
1069
1096
|
},
|
|
1070
|
-
gemini: {
|
|
1071
|
-
relativePath: 'GEMINI.md',
|
|
1072
|
-
snippetPath: 'dflow/specs/shared/GEMINI-md-snippet.md'
|
|
1073
|
-
},
|
|
1074
1097
|
copilot: {
|
|
1075
1098
|
relativePath: '.github/copilot-instructions.md',
|
|
1076
1099
|
snippetPath: 'dflow/specs/shared/copilot-instructions-snippet.md'
|
|
@@ -1080,12 +1103,16 @@ function getAiAgentTarget(agent) {
|
|
|
1080
1103
|
return targets[agent];
|
|
1081
1104
|
}
|
|
1082
1105
|
|
|
1083
|
-
function buildAiAgentShim(targetPath) {
|
|
1106
|
+
function buildAiAgentShim(targetPath, commandRegistry = []) {
|
|
1084
1107
|
const title = targetPath === '.github/copilot-instructions.md'
|
|
1085
1108
|
? 'GitHub Copilot Repository Instructions'
|
|
1086
1109
|
: `${targetPath} - Dflow Project Instructions`;
|
|
1087
1110
|
|
|
1088
|
-
const
|
|
1111
|
+
const commandTriggerHint = targetPath === 'AGENTS.md' && commandRegistry.length > 0
|
|
1112
|
+
? buildCodexCommandTriggerSection(commandRegistry)
|
|
1113
|
+
: '';
|
|
1114
|
+
|
|
1115
|
+
const importHint = targetPath === 'CLAUDE.md'
|
|
1089
1116
|
? '\nIf your tool supports Markdown imports, the canonical guide is imported below:\n\n@dflow/specs/shared/AI-AGENT-GUIDE.md\n'
|
|
1090
1117
|
: '';
|
|
1091
1118
|
|
|
@@ -1099,10 +1126,195 @@ Before planning or editing code, read and follow:
|
|
|
1099
1126
|
|
|
1100
1127
|
Keep tool-specific instruction files small. The Dflow guide above is the
|
|
1101
1128
|
single source of truth for project workflow rules, slash-command behavior,
|
|
1102
|
-
spec locations, and SDD/DDD constraints.${importHint}
|
|
1129
|
+
spec locations, and SDD/DDD constraints.${commandTriggerHint}${importHint}
|
|
1103
1130
|
`;
|
|
1104
1131
|
}
|
|
1105
1132
|
|
|
1133
|
+
function addCommandAdapterItems(items, aiAgents, commandRegistry) {
|
|
1134
|
+
if (aiAgents.includes('claude')) {
|
|
1135
|
+
for (const command of commandRegistry) {
|
|
1136
|
+
items.push({
|
|
1137
|
+
relativePath: `.claude/commands/dflow/dflow-${command.id}.md`,
|
|
1138
|
+
source: 'generated:claude-command-adapter',
|
|
1139
|
+
notes: 'command adapter, derived from dflow command registry',
|
|
1140
|
+
content: buildThinCommandWrapper(command),
|
|
1141
|
+
overwrite: true
|
|
1142
|
+
});
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
if (aiAgents.includes('copilot')) {
|
|
1147
|
+
for (const command of commandRegistry) {
|
|
1148
|
+
items.push({
|
|
1149
|
+
relativePath: `.github/prompts/dflow-${command.id}.prompt.md`,
|
|
1150
|
+
source: 'generated:copilot-command-adapter',
|
|
1151
|
+
notes: 'command adapter, derived from dflow command registry',
|
|
1152
|
+
content: buildThinCommandWrapper(command),
|
|
1153
|
+
overwrite: true
|
|
1154
|
+
});
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
function buildCodexCommandTriggerSection(commandRegistry) {
|
|
1160
|
+
const triggers = commandRegistry
|
|
1161
|
+
.map((command) => {
|
|
1162
|
+
const commandKind = command.scope === 'control' ? 'command' : 'workflow';
|
|
1163
|
+
return `- \`${command.label}\` as text, or "Run the Dflow ${command.label} ${commandKind}."`;
|
|
1164
|
+
})
|
|
1165
|
+
.join('\n');
|
|
1166
|
+
|
|
1167
|
+
return `
|
|
1168
|
+
|
|
1169
|
+
## Dflow Text Triggers
|
|
1170
|
+
|
|
1171
|
+
Codex does not install Dflow command files. When the developer asks for a
|
|
1172
|
+
canonical Dflow command, treat it as a text trigger, read the canonical guide,
|
|
1173
|
+
and execute the matching workflow or control command.
|
|
1174
|
+
|
|
1175
|
+
Recognized canonical triggers:
|
|
1176
|
+
|
|
1177
|
+
${triggers}
|
|
1178
|
+
`;
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
function buildThinCommandWrapper(command) {
|
|
1182
|
+
const argHint = command.argHint === '-'
|
|
1183
|
+
? 'Argument hint: none.'
|
|
1184
|
+
: `Argument hint: ${command.argHint}.`;
|
|
1185
|
+
|
|
1186
|
+
return `# /dflow-${command.id}
|
|
1187
|
+
|
|
1188
|
+
Execute the canonical \`${command.label}\` Dflow workflow or control command.
|
|
1189
|
+
|
|
1190
|
+
Definition: \`dflow/specs/shared/AI-AGENT-GUIDE.md\`
|
|
1191
|
+
|
|
1192
|
+
${argHint}
|
|
1193
|
+
`;
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
function parseDflowCommandRegistry(content) {
|
|
1197
|
+
const start = content.indexOf(COMMAND_REGISTRY_START);
|
|
1198
|
+
const end = content.indexOf(COMMAND_REGISTRY_END);
|
|
1199
|
+
|
|
1200
|
+
if (start === -1 || end === -1 || end <= start) {
|
|
1201
|
+
throw new InitError('Internal error: dflow command registry markers not found in packaged AI-AGENT-GUIDE.md.');
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
const registryContent = content.slice(start + COMMAND_REGISTRY_START.length, end);
|
|
1205
|
+
const tableLines = registryContent
|
|
1206
|
+
.split(/\r?\n/)
|
|
1207
|
+
.map((line) => line.trim())
|
|
1208
|
+
.filter((line) => line.startsWith('|') && line.endsWith('|'));
|
|
1209
|
+
|
|
1210
|
+
if (tableLines.length < 3) {
|
|
1211
|
+
throw new InitError('Internal error: dflow command registry table is empty.');
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
const header = parseMarkdownTableRow(tableLines[0]).map((cell) => cell.toLowerCase());
|
|
1215
|
+
const expectedHeader = ['id', 'label', 'description', 'arg-hint', 'scope'];
|
|
1216
|
+
if (header.length !== expectedHeader.length || !expectedHeader.every((cell, index) => header[index] === cell)) {
|
|
1217
|
+
throw new InitError('Internal error: dflow command registry header must be: id, label, description, arg-hint, scope.');
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
const delimiter = parseMarkdownTableRow(tableLines[1]);
|
|
1221
|
+
if (delimiter.length !== expectedHeader.length || !delimiter.every((cell) => /^:?-{3,}:?$/.test(cell))) {
|
|
1222
|
+
throw new InitError('Internal error: dflow command registry delimiter row is invalid.');
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
const commands = [];
|
|
1226
|
+
const seen = new Set();
|
|
1227
|
+
|
|
1228
|
+
for (const line of tableLines.slice(2)) {
|
|
1229
|
+
const cells = parseMarkdownTableRow(line);
|
|
1230
|
+
if (cells.length !== expectedHeader.length) {
|
|
1231
|
+
throw new InitError(`Internal error: invalid dflow command registry row: ${line}`);
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
const command = {
|
|
1235
|
+
id: stripInlineCode(cells[0]),
|
|
1236
|
+
label: stripInlineCode(cells[1]),
|
|
1237
|
+
description: stripInlineCode(cells[2]),
|
|
1238
|
+
argHint: stripInlineCode(cells[3]),
|
|
1239
|
+
scope: stripInlineCode(cells[4])
|
|
1240
|
+
};
|
|
1241
|
+
|
|
1242
|
+
validateDflowCommandRegistryRow(command, seen);
|
|
1243
|
+
commands.push(command);
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
const actualIds = commands.map((command) => command.id);
|
|
1247
|
+
const missingIds = EXPECTED_COMMAND_IDS.filter((id) => !actualIds.includes(id));
|
|
1248
|
+
const extraIds = actualIds.filter((id) => !EXPECTED_COMMAND_IDS.includes(id));
|
|
1249
|
+
if (missingIds.length > 0 || extraIds.length > 0 || commands.length !== EXPECTED_COMMAND_IDS.length) {
|
|
1250
|
+
throw new InitError(
|
|
1251
|
+
`Internal error: dflow command registry must contain exactly these command ids: ${EXPECTED_COMMAND_IDS.join(', ')}.`
|
|
1252
|
+
);
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
return commands;
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
function parseMarkdownTableRow(line) {
|
|
1259
|
+
const trimmed = line.trim();
|
|
1260
|
+
const inner = trimmed.slice(1, -1);
|
|
1261
|
+
const cells = [];
|
|
1262
|
+
let current = '';
|
|
1263
|
+
|
|
1264
|
+
for (let index = 0; index < inner.length; index += 1) {
|
|
1265
|
+
const char = inner[index];
|
|
1266
|
+
const next = inner[index + 1];
|
|
1267
|
+
|
|
1268
|
+
if (char === '\\' && next === '|') {
|
|
1269
|
+
current += '|';
|
|
1270
|
+
index += 1;
|
|
1271
|
+
continue;
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
if (char === '|') {
|
|
1275
|
+
cells.push(current.trim());
|
|
1276
|
+
current = '';
|
|
1277
|
+
continue;
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
current += char;
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
cells.push(current.trim());
|
|
1284
|
+
return cells;
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
function stripInlineCode(value) {
|
|
1288
|
+
const trimmed = String(value || '').trim();
|
|
1289
|
+
if (trimmed.startsWith('`') && trimmed.endsWith('`') && trimmed.length >= 2) {
|
|
1290
|
+
return trimmed.slice(1, -1);
|
|
1291
|
+
}
|
|
1292
|
+
return trimmed;
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
function validateDflowCommandRegistryRow(command, seen) {
|
|
1296
|
+
if (!/^[a-z][a-z0-9-]*$/.test(command.id)) {
|
|
1297
|
+
throw new InitError(`Internal error: invalid dflow command id: ${command.id}`);
|
|
1298
|
+
}
|
|
1299
|
+
if (seen.has(command.id)) {
|
|
1300
|
+
throw new InitError(`Internal error: duplicate dflow command id: ${command.id}`);
|
|
1301
|
+
}
|
|
1302
|
+
seen.add(command.id);
|
|
1303
|
+
|
|
1304
|
+
if (command.label !== `/dflow:${command.id}`) {
|
|
1305
|
+
throw new InitError(`Internal error: dflow command label must be /dflow:${command.id}.`);
|
|
1306
|
+
}
|
|
1307
|
+
if (!command.description) {
|
|
1308
|
+
throw new InitError(`Internal error: dflow command ${command.id} is missing a description.`);
|
|
1309
|
+
}
|
|
1310
|
+
if (!command.argHint) {
|
|
1311
|
+
throw new InitError(`Internal error: dflow command ${command.id} is missing an arg-hint.`);
|
|
1312
|
+
}
|
|
1313
|
+
if (!command.scope) {
|
|
1314
|
+
throw new InitError(`Internal error: dflow command ${command.id} is missing a scope.`);
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1106
1318
|
function buildDeferredItems(edition) {
|
|
1107
1319
|
const deferred = [...DEFERRED_COMMON];
|
|
1108
1320
|
if (edition === 'greenfield') {
|
|
@@ -1433,6 +1645,7 @@ function renderPreview(stdout, plan, warnings) {
|
|
|
1433
1645
|
async function writeFilePlan(cwd, plan) {
|
|
1434
1646
|
const result = {
|
|
1435
1647
|
created: [],
|
|
1648
|
+
updated: [],
|
|
1436
1649
|
skipped: [],
|
|
1437
1650
|
warnings: []
|
|
1438
1651
|
};
|
|
@@ -1442,6 +1655,13 @@ async function writeFilePlan(cwd, plan) {
|
|
|
1442
1655
|
|
|
1443
1656
|
try {
|
|
1444
1657
|
if (await pathExists(targetPath)) {
|
|
1658
|
+
if (item.overwrite) {
|
|
1659
|
+
await fs.mkdir(path.dirname(targetPath), { recursive: true });
|
|
1660
|
+
await fs.writeFile(targetPath, item.content);
|
|
1661
|
+
result.updated.push(item.relativePath);
|
|
1662
|
+
continue;
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1445
1665
|
result.skipped.push(item.relativePath);
|
|
1446
1666
|
result.warnings.push(`Skipped existing target: ${item.relativePath}`);
|
|
1447
1667
|
if (item.relativePath === 'dflow/specs/shared/_conventions.md') {
|
|
@@ -1528,6 +1748,9 @@ function printResultReport(stdout, result, deferred) {
|
|
|
1528
1748
|
stdout.write('\nCreated:\n');
|
|
1529
1749
|
printList(stdout, result.created);
|
|
1530
1750
|
|
|
1751
|
+
stdout.write('\nUpdated:\n');
|
|
1752
|
+
printList(stdout, result.updated);
|
|
1753
|
+
|
|
1531
1754
|
stdout.write('\nSkipped:\n');
|
|
1532
1755
|
printList(stdout, result.skipped);
|
|
1533
1756
|
|
|
@@ -1552,7 +1775,11 @@ Recommended next steps:
|
|
|
1552
1775
|
`);
|
|
1553
1776
|
}
|
|
1554
1777
|
|
|
1555
|
-
function printConfigureAgentsNextSteps(stdout) {
|
|
1778
|
+
function printConfigureAgentsNextSteps(stdout, commandAdapters = false) {
|
|
1779
|
+
const commandAdapterStep = commandAdapters
|
|
1780
|
+
? '- Command adapters use adapter-native names such as `/dflow-new-feature`; canonical `/dflow:*` names remain defined in dflow/specs/shared/AI-AGENT-GUIDE.md.\n'
|
|
1781
|
+
: '';
|
|
1782
|
+
|
|
1556
1783
|
stdout.write(`
|
|
1557
1784
|
Dflow AI agent configuration complete.
|
|
1558
1785
|
|
|
@@ -1560,6 +1787,7 @@ Recommended next steps:
|
|
|
1560
1787
|
- Keep AI-agent-specific root files small.
|
|
1561
1788
|
- Put durable workflow changes in dflow/specs/shared/AI-AGENT-GUIDE.md.
|
|
1562
1789
|
- If a merge snippet was created, review it and merge the pointer into the existing tool instruction file.
|
|
1790
|
+
${commandAdapterStep}
|
|
1563
1791
|
`);
|
|
1564
1792
|
}
|
|
1565
1793
|
|
package/package.json
CHANGED
|
@@ -31,6 +31,45 @@ are not available in the current AI tool:
|
|
|
31
31
|
| `/dflow:verify` | Specs, domain docs, implementation, and tests need consistency checks. |
|
|
32
32
|
| `/dflow:pr-review` | A change is ready for SDD/DDD review. |
|
|
33
33
|
| `/dflow:report-dflow-feedback` | You found a Dflow issue or improvement and want a sanitized upstream feedback draft. |
|
|
34
|
+
| `/dflow:status` | You need the current workflow state, current step, completed work, in-progress work, remaining work, pending decision, and next valid action. |
|
|
35
|
+
| `/dflow:next` | An active workflow is waiting at a step gate and the developer confirms continuing to the next step. |
|
|
36
|
+
| `/dflow:cancel` | The developer wants to abort the current workflow and return to free conversation without rollback. |
|
|
37
|
+
|
|
38
|
+
Machine-readable source for rendering tool-specific thin wrappers:
|
|
39
|
+
|
|
40
|
+
<!-- dflow-command-registry:start -->
|
|
41
|
+
| id | label | description | arg-hint | scope |
|
|
42
|
+
|---|---|---|---|---|
|
|
43
|
+
| new-feature | /dflow:new-feature | Start a new user-visible feature or business behavior. | feature request | workflow |
|
|
44
|
+
| modify-existing | /dflow:modify-existing | Change existing behavior. | change request | workflow |
|
|
45
|
+
| bug-fix | /dflow:bug-fix | Investigate a defect described by expected vs actual behavior. | expected vs actual | workflow |
|
|
46
|
+
| new-phase | /dflow:new-phase | Add another implementation slice to an active feature. | feature id or phase goal | workflow |
|
|
47
|
+
| finish-feature | /dflow:finish-feature | Close implementation with drift checks and archived feature state. | feature id | workflow |
|
|
48
|
+
| verify | /dflow:verify | Check specs, domain docs, implementation, and tests for consistency. | area or feature id | workflow |
|
|
49
|
+
| pr-review | /dflow:pr-review | Review a ready change for SDD/DDD alignment. | change or branch | workflow |
|
|
50
|
+
| report-dflow-feedback | /dflow:report-dflow-feedback | Draft sanitized upstream feedback about Dflow. | issue or improvement | workflow |
|
|
51
|
+
| status | /dflow:status | Report current workflow state and next valid action. | - | control |
|
|
52
|
+
| next | /dflow:next | Confirm the active step gate and continue. | - | control |
|
|
53
|
+
| cancel | /dflow:cancel | Abort the active workflow and return to free conversation. | - | control |
|
|
54
|
+
<!-- dflow-command-registry:end -->
|
|
55
|
+
|
|
56
|
+
## Status / Control Commands
|
|
57
|
+
|
|
58
|
+
`/dflow:status` reports active workflow state. Include these fields: workflow,
|
|
59
|
+
step, completed, in-progress, remaining, pending decision, and next valid action.
|
|
60
|
+
If no workflow is active, say that no workflow is active and list valid flow-entry
|
|
61
|
+
or standalone commands.
|
|
62
|
+
|
|
63
|
+
`/dflow:next` is valid only at a step gate in an active workflow. Treat it as
|
|
64
|
+
developer confirmation equivalent to "OK" or "continue", then move to the next
|
|
65
|
+
workflow step.
|
|
66
|
+
|
|
67
|
+
`/dflow:cancel` aborts the current workflow and returns to free conversation.
|
|
68
|
+
Do not rollback changes, delete artifacts, or rewrite specs merely because the
|
|
69
|
+
workflow was cancelled.
|
|
70
|
+
|
|
71
|
+
When no workflow is active, `/dflow:next` and `/dflow:cancel` must report that
|
|
72
|
+
there is no active workflow to advance or cancel.
|
|
34
73
|
|
|
35
74
|
## Source of Truth
|
|
36
75
|
|
|
@@ -85,9 +124,9 @@ review is required.
|
|
|
85
124
|
## Tool-Specific Notes
|
|
86
125
|
|
|
87
126
|
This file is the canonical Dflow guide. Root-level files such as
|
|
88
|
-
`AGENTS.md`, `CLAUDE.md`,
|
|
127
|
+
`AGENTS.md`, `CLAUDE.md`, and `.github/copilot-instructions.md`
|
|
89
128
|
should stay thin and point back here.
|
|
90
129
|
|
|
91
130
|
If a tool does not support Dflow slash commands, treat the command names as
|
|
92
|
-
plain workflow names
|
|
93
|
-
|
|
131
|
+
plain workflow names. This guide contains the installed runtime behavior
|
|
132
|
+
contract; execute the workflow semantics defined here directly.
|
|
@@ -31,6 +31,45 @@ are not available in the current AI tool:
|
|
|
31
31
|
| `/dflow:verify` | Specs, domain docs, implementation, and tests need consistency checks. |
|
|
32
32
|
| `/dflow:pr-review` | A change is ready for SDD/DDD review. |
|
|
33
33
|
| `/dflow:report-dflow-feedback` | You found a Dflow issue or improvement and want a sanitized upstream feedback draft. |
|
|
34
|
+
| `/dflow:status` | You need the current workflow state, current step, completed work, in-progress work, remaining work, pending decision, and next valid action. |
|
|
35
|
+
| `/dflow:next` | An active workflow is waiting at a step gate and the developer confirms continuing to the next step. |
|
|
36
|
+
| `/dflow:cancel` | The developer wants to abort the current workflow and return to free conversation without rollback. |
|
|
37
|
+
|
|
38
|
+
Machine-readable source for rendering tool-specific thin wrappers:
|
|
39
|
+
|
|
40
|
+
<!-- dflow-command-registry:start -->
|
|
41
|
+
| id | label | description | arg-hint | scope |
|
|
42
|
+
|---|---|---|---|---|
|
|
43
|
+
| new-feature | /dflow:new-feature | Start a new user-visible feature or business behavior. | feature request | workflow |
|
|
44
|
+
| modify-existing | /dflow:modify-existing | Change existing behavior. | change request | workflow |
|
|
45
|
+
| bug-fix | /dflow:bug-fix | Investigate a defect described by expected vs actual behavior. | expected vs actual | workflow |
|
|
46
|
+
| new-phase | /dflow:new-phase | Add another implementation slice to an active feature. | feature id or phase goal | workflow |
|
|
47
|
+
| finish-feature | /dflow:finish-feature | Close implementation with drift checks and archived feature state. | feature id | workflow |
|
|
48
|
+
| verify | /dflow:verify | Check specs, domain docs, implementation, and tests for consistency. | area or feature id | workflow |
|
|
49
|
+
| pr-review | /dflow:pr-review | Review a ready change for SDD/DDD alignment. | change or branch | workflow |
|
|
50
|
+
| report-dflow-feedback | /dflow:report-dflow-feedback | Draft sanitized upstream feedback about Dflow. | issue or improvement | workflow |
|
|
51
|
+
| status | /dflow:status | Report current workflow state and next valid action. | - | control |
|
|
52
|
+
| next | /dflow:next | Confirm the active step gate and continue. | - | control |
|
|
53
|
+
| cancel | /dflow:cancel | Abort the active workflow and return to free conversation. | - | control |
|
|
54
|
+
<!-- dflow-command-registry:end -->
|
|
55
|
+
|
|
56
|
+
## Status / Control Commands
|
|
57
|
+
|
|
58
|
+
`/dflow:status` reports active workflow state. Include these fields: workflow,
|
|
59
|
+
step, completed, in-progress, remaining, pending decision, and next valid action.
|
|
60
|
+
If no workflow is active, say that no workflow is active and list valid flow-entry
|
|
61
|
+
or standalone commands.
|
|
62
|
+
|
|
63
|
+
`/dflow:next` is valid only at a step gate in an active workflow. Treat it as
|
|
64
|
+
developer confirmation equivalent to "OK" or "continue", then move to the next
|
|
65
|
+
workflow step.
|
|
66
|
+
|
|
67
|
+
`/dflow:cancel` aborts the current workflow and returns to free conversation.
|
|
68
|
+
Do not rollback changes, delete artifacts, or rewrite specs merely because the
|
|
69
|
+
workflow was cancelled.
|
|
70
|
+
|
|
71
|
+
When no workflow is active, `/dflow:next` and `/dflow:cancel` must report that
|
|
72
|
+
there is no active workflow to advance or cancel.
|
|
34
73
|
|
|
35
74
|
## Source of Truth
|
|
36
75
|
|
|
@@ -85,9 +124,9 @@ review is required.
|
|
|
85
124
|
## Tool-Specific Notes
|
|
86
125
|
|
|
87
126
|
This file is the canonical Dflow guide. Root-level files such as
|
|
88
|
-
`AGENTS.md`, `CLAUDE.md`,
|
|
127
|
+
`AGENTS.md`, `CLAUDE.md`, and `.github/copilot-instructions.md`
|
|
89
128
|
should stay thin and point back here.
|
|
90
129
|
|
|
91
130
|
If a tool does not support Dflow slash commands, treat the command names as
|
|
92
|
-
plain workflow names
|
|
93
|
-
|
|
131
|
+
plain workflow names. This guide contains the installed runtime behavior
|
|
132
|
+
contract; execute the workflow semantics defined here directly.
|
|
@@ -109,6 +109,7 @@ AI 的完整決策樹、Workflow Transparency、Ceremony Scaling 三層判準
|
|
|
109
109
|
- `/dflow:finish-feature` — Feature 收尾 + 整合摘要
|
|
110
110
|
- `/dflow:pr-review` — PR 審查檢查點
|
|
111
111
|
- `/dflow:report-dflow-feedback` — 草擬給 Dflow upstream 的已清理回饋,不自動送出
|
|
112
|
+
- `/dflow:status` / `/dflow:next` / `/dflow:cancel` — 狀態管理
|
|
112
113
|
|
|
113
114
|
### Core Principles (Project Reaffirmed)
|
|
114
115
|
|