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/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
- item.action = (await pathExists(absolute)) ? 'skip' : 'create';
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 relativePath = targetExists && !targetConfigured ? target.snippetPath : target.relativePath;
1034
- const content = substitutePlaceholders(buildAiAgentShim(target.relativePath), substitution);
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 importHint = targetPath === 'CLAUDE.md' || targetPath === 'GEMINI.md'
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dflow-sdd-ddd",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Spec-first SDD/DDD workflow kit for AI-assisted development",
5
5
  "type": "commonjs",
6
6
  "bin": {
@@ -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`, `GEMINI.md`, and `.github/copilot-instructions.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 and execute the matching process from the Dflow skill
93
- source in this repository.
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`, `GEMINI.md`, and `.github/copilot-instructions.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 and execute the matching process from the Dflow skill
93
- source in this repository.
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