@haaaiawd/anws 2.1.0 → 2.1.1
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/bin/cli.js +11 -5
- package/lib/changelog.js +78 -7
- package/lib/diff.js +17 -0
- package/lib/update.js +21 -75
- package/package.json +1 -1
- package/templates/.agents/skills/design-reviewer/SKILL.md +22 -7
- package/templates/.agents/skills/system-designer/references/system-design-template.md +19 -2
- package/templates/.agents/skills/task-reviewer/SKILL.md +46 -19
- package/templates/.agents/workflows/challenge.md +170 -149
- package/templates/.agents/workflows/change.md +1 -1
- package/templates/.agents/workflows/design-system.md +24 -0
- package/templates/.agents/workflows/forge.md +44 -20
- package/templates/.agents/workflows/genesis.md +49 -4
- package/templates/.agents/workflows/quickstart.md +46 -2
package/bin/cli.js
CHANGED
|
@@ -22,8 +22,7 @@ COMMANDS
|
|
|
22
22
|
OPTIONS
|
|
23
23
|
-v, --version Print version number
|
|
24
24
|
-h, --help Show this help message
|
|
25
|
-
--target Target AI IDE(s) for
|
|
26
|
-
--check Preview grouped update diffs without writing files or rebuilding install-lock state
|
|
25
|
+
--target Target AI IDE(s) for init, comma-separated (${TARGET_IDS.join(', ')})
|
|
27
26
|
|
|
28
27
|
SUPPORTED TARGETS
|
|
29
28
|
windsurf workflows + skills
|
|
@@ -40,8 +39,7 @@ SUPPORTED TARGETS
|
|
|
40
39
|
EXAMPLES
|
|
41
40
|
anws init # Choose target IDEs and install their managed workflow projections
|
|
42
41
|
anws init --target windsurf,codex,opencode
|
|
43
|
-
anws update #
|
|
44
|
-
anws update --check # Preview grouped changes per target without writing files
|
|
42
|
+
anws update # One-click update for all matched targets from install-lock, fallback scan, or drift repair
|
|
45
43
|
`.trimStart();
|
|
46
44
|
|
|
47
45
|
// ─── 参数解析 ─────────────────────────────────────────────────────────────────
|
|
@@ -90,7 +88,15 @@ async function main() {
|
|
|
90
88
|
break;
|
|
91
89
|
|
|
92
90
|
case 'update':
|
|
93
|
-
|
|
91
|
+
if (values.target !== undefined) {
|
|
92
|
+
error('`anws update --target` has been removed. Use `anws update` to update all matched targets.');
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
if (values.check) {
|
|
96
|
+
error('`anws update --check` has been removed. Use `anws update` directly.');
|
|
97
|
+
process.exit(1);
|
|
98
|
+
}
|
|
99
|
+
await require('../lib/update')();
|
|
94
100
|
break;
|
|
95
101
|
|
|
96
102
|
default:
|
package/lib/changelog.js
CHANGED
|
@@ -55,6 +55,61 @@ function compareSemver(a, b) {
|
|
|
55
55
|
return 0;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
function normalizeText(text) {
|
|
59
|
+
return String(text || '').replace(/\r\n/g, '\n');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function buildMergedChangeKey(item) {
|
|
63
|
+
const canonicalPath = item.source || item.file;
|
|
64
|
+
const summaryKey = JSON.stringify(item.summary || []);
|
|
65
|
+
const contentKey = item.type === 'modified'
|
|
66
|
+
? summaryKey
|
|
67
|
+
: `${normalizeText(item.oldContent)}\n<<<ANWS_CHANGE_SPLIT>>>\n${normalizeText(item.newContent)}`;
|
|
68
|
+
|
|
69
|
+
return `${item.type}::${canonicalPath}::${item.resourceId || canonicalPath}::${contentKey}`;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function mergeChanges(changes) {
|
|
73
|
+
const grouped = new Map();
|
|
74
|
+
|
|
75
|
+
for (const item of changes) {
|
|
76
|
+
const canonicalPath = item.source || item.file;
|
|
77
|
+
const key = buildMergedChangeKey(item);
|
|
78
|
+
const affectedFile = {
|
|
79
|
+
file: item.file,
|
|
80
|
+
targetId: item.targetId || null,
|
|
81
|
+
targetLabel: item.targetLabel || null
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
if (!grouped.has(key)) {
|
|
85
|
+
grouped.set(key, {
|
|
86
|
+
...item,
|
|
87
|
+
canonicalPath,
|
|
88
|
+
affectedFiles: [affectedFile]
|
|
89
|
+
});
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const current = grouped.get(key);
|
|
94
|
+
current.affectedFiles.push(affectedFile);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return Array.from(grouped.values()).map((item) => ({
|
|
98
|
+
...item,
|
|
99
|
+
affectedFiles: item.affectedFiles.sort((left, right) => left.file.localeCompare(right.file))
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function formatAffectedTargetList(item) {
|
|
104
|
+
const targets = Array.from(new Set(
|
|
105
|
+
item.affectedFiles
|
|
106
|
+
.filter((entry) => entry.targetId && entry.targetLabel)
|
|
107
|
+
.map((entry) => `${entry.targetLabel} (${entry.targetId})`)
|
|
108
|
+
));
|
|
109
|
+
|
|
110
|
+
return targets.length > 0 ? targets.join(', ') : '无';
|
|
111
|
+
}
|
|
112
|
+
|
|
58
113
|
function formatFileList(title, items) {
|
|
59
114
|
const lines = [`### ${title}`];
|
|
60
115
|
if (items.length === 0) {
|
|
@@ -63,7 +118,10 @@ function formatFileList(title, items) {
|
|
|
63
118
|
}
|
|
64
119
|
|
|
65
120
|
for (const item of items) {
|
|
66
|
-
lines.push(`- \`${item.
|
|
121
|
+
lines.push(`- \`${item.canonicalPath}\` — 影响 Targets: ${formatAffectedTargetList(item)}`);
|
|
122
|
+
for (const affectedFile of item.affectedFiles) {
|
|
123
|
+
lines.push(` - \`${affectedFile.file}\``);
|
|
124
|
+
}
|
|
67
125
|
}
|
|
68
126
|
|
|
69
127
|
return lines.join('\n');
|
|
@@ -72,7 +130,10 @@ function formatFileList(title, items) {
|
|
|
72
130
|
function formatDetail(item) {
|
|
73
131
|
if (item.type === 'added') {
|
|
74
132
|
return [
|
|
75
|
-
`### \`${item.
|
|
133
|
+
`### \`${item.canonicalPath}\``,
|
|
134
|
+
`- **影响 Targets**: ${formatAffectedTargetList(item)}`,
|
|
135
|
+
'- **影响文件**:',
|
|
136
|
+
...item.affectedFiles.map((entry) => ` - \`${entry.file}\``),
|
|
76
137
|
'- **新增文件**',
|
|
77
138
|
'- **说明**: 该文件在旧版本中不存在,因此无前后逐行对比。'
|
|
78
139
|
].join('\n');
|
|
@@ -80,7 +141,10 @@ function formatDetail(item) {
|
|
|
80
141
|
|
|
81
142
|
if (item.type === 'deleted') {
|
|
82
143
|
return [
|
|
83
|
-
`### \`${item.
|
|
144
|
+
`### \`${item.canonicalPath}\``,
|
|
145
|
+
`- **影响 Targets**: ${formatAffectedTargetList(item)}`,
|
|
146
|
+
'- **影响文件**:',
|
|
147
|
+
...item.affectedFiles.map((entry) => ` - \`${entry.file}\``),
|
|
84
148
|
'- **删除文件**',
|
|
85
149
|
'- **说明**: 该文件在新版本中不存在,因此无前后逐行对比。'
|
|
86
150
|
].join('\n');
|
|
@@ -88,13 +152,19 @@ function formatDetail(item) {
|
|
|
88
152
|
|
|
89
153
|
if (item.summary.length === 0) {
|
|
90
154
|
return [
|
|
91
|
-
`### \`${item.
|
|
155
|
+
`### \`${item.canonicalPath}\``,
|
|
156
|
+
`- **影响 Targets**: ${formatAffectedTargetList(item)}`,
|
|
157
|
+
'- **影响文件**:',
|
|
158
|
+
...item.affectedFiles.map((entry) => ` - \`${entry.file}\``),
|
|
92
159
|
'- **说明**: 检测到内容变更,但未能提取到摘要。'
|
|
93
160
|
].join('\n');
|
|
94
161
|
}
|
|
95
162
|
|
|
96
163
|
return [
|
|
97
|
-
`### \`${item.
|
|
164
|
+
`### \`${item.canonicalPath}\``,
|
|
165
|
+
`- **影响 Targets**: ${formatAffectedTargetList(item)}`,
|
|
166
|
+
'- **影响文件**:',
|
|
167
|
+
...item.affectedFiles.map((entry) => ` - \`${entry.file}\``),
|
|
98
168
|
'```diff',
|
|
99
169
|
...item.summary.flatMap((pair) => [
|
|
100
170
|
`- [old:${pair.oldLineNumber === null ? '-' : pair.oldLineNumber}] ${pair.oldText}`,
|
|
@@ -106,7 +176,8 @@ function formatDetail(item) {
|
|
|
106
176
|
|
|
107
177
|
async function generateChangelog({ cwd, version, changes, targetSummary = null }) {
|
|
108
178
|
const changelogDir = await ensureChangelogDir(cwd);
|
|
109
|
-
const
|
|
179
|
+
const mergedChanges = mergeChanges(changes);
|
|
180
|
+
const grouped = groupChanges(mergedChanges);
|
|
110
181
|
const now = new Date();
|
|
111
182
|
const timestamp = now.toISOString().replace('T', ' ').slice(0, 19);
|
|
112
183
|
const filePath = path.join(changelogDir, `v${version}.md`);
|
|
@@ -143,7 +214,7 @@ async function generateChangelog({ cwd, version, changes, targetSummary = null }
|
|
|
143
214
|
'',
|
|
144
215
|
'## 内容级变更详情',
|
|
145
216
|
'',
|
|
146
|
-
...(
|
|
217
|
+
...(mergedChanges.length > 0 ? mergedChanges.map(formatDetail).flatMap((section) => [section, '']) : ['- 无变更', ''])
|
|
147
218
|
].join('\n');
|
|
148
219
|
|
|
149
220
|
await fs.writeFile(filePath, content, 'utf8');
|
package/lib/diff.js
CHANGED
|
@@ -137,6 +137,7 @@ async function collectManagedFileDiffs({
|
|
|
137
137
|
? managedFiles
|
|
138
138
|
: projectionPlan.flatMap((item) => item.managedFiles || []);
|
|
139
139
|
const projectionMap = new Map(normalizedProjectionEntries.map((item) => [item.outputPath, item]));
|
|
140
|
+
const fallbackTarget = projectionPlan[0] || null;
|
|
140
141
|
|
|
141
142
|
for (const rel of normalizedManagedFiles) {
|
|
142
143
|
if (rel === 'AGENTS.md' && !shouldWriteRootAgents) {
|
|
@@ -144,6 +145,19 @@ async function collectManagedFileDiffs({
|
|
|
144
145
|
}
|
|
145
146
|
|
|
146
147
|
const entry = projectionMap.get(rel);
|
|
148
|
+
const metadata = entry
|
|
149
|
+
? {
|
|
150
|
+
source: entry.source,
|
|
151
|
+
resourceId: entry.id,
|
|
152
|
+
targetId: entry.targetId,
|
|
153
|
+
targetLabel: entry.targetLabel
|
|
154
|
+
}
|
|
155
|
+
: {
|
|
156
|
+
source: rel,
|
|
157
|
+
resourceId: rel === 'AGENTS.md' ? 'root-agents' : rel,
|
|
158
|
+
targetId: fallbackTarget?.targetId || null,
|
|
159
|
+
targetLabel: fallbackTarget?.targetLabel || null
|
|
160
|
+
};
|
|
147
161
|
const srcPath = rel === 'AGENTS.md'
|
|
148
162
|
? srcAgents
|
|
149
163
|
: path.join(path.join(__dirname, '..', 'templates'), entry.source);
|
|
@@ -160,6 +174,7 @@ async function collectManagedFileDiffs({
|
|
|
160
174
|
if (srcExists && !destExists) {
|
|
161
175
|
results.push({
|
|
162
176
|
file: rel,
|
|
177
|
+
...metadata,
|
|
163
178
|
type: 'added',
|
|
164
179
|
summary: [],
|
|
165
180
|
oldContent: '',
|
|
@@ -171,6 +186,7 @@ async function collectManagedFileDiffs({
|
|
|
171
186
|
if (!srcExists && destExists) {
|
|
172
187
|
results.push({
|
|
173
188
|
file: rel,
|
|
189
|
+
...metadata,
|
|
174
190
|
type: 'deleted',
|
|
175
191
|
summary: [],
|
|
176
192
|
oldContent: await readTextOrEmpty(destPath),
|
|
@@ -193,6 +209,7 @@ async function collectManagedFileDiffs({
|
|
|
193
209
|
|
|
194
210
|
results.push({
|
|
195
211
|
file: rel,
|
|
212
|
+
...metadata,
|
|
196
213
|
type: 'modified',
|
|
197
214
|
summary: createLineDiff(oldContent, newContent),
|
|
198
215
|
oldContent,
|
package/lib/update.js
CHANGED
|
@@ -5,32 +5,33 @@ const path = require('node:path');
|
|
|
5
5
|
const { buildProjectionPlan } = require('./manifest');
|
|
6
6
|
const { getTarget } = require('./adapters');
|
|
7
7
|
const { planAgentsUpdate, resolveAgentsInstall, printLegacyMigrationWarning, pathExists } = require('./agents');
|
|
8
|
-
const { collectManagedFileDiffs
|
|
8
|
+
const { collectManagedFileDiffs } = require('./diff');
|
|
9
9
|
const { detectUpgrade, generateChangelog } = require('./changelog');
|
|
10
10
|
const { writeTargetFiles } = require('./copy');
|
|
11
11
|
const { createInstallLock, dedupeTargets, detectInstallState, summarizeTargetState, writeInstallLock } = require('./install-state');
|
|
12
12
|
const { confirm } = require('./prompt');
|
|
13
13
|
const { ROOT_AGENTS_FILE, resolveCanonicalSource } = require('./resources');
|
|
14
|
-
const {
|
|
14
|
+
const { warn, error, info, fileLine, skippedLine, blank, logo, section } = require('./output');
|
|
15
15
|
|
|
16
|
-
async function update(
|
|
16
|
+
async function update() {
|
|
17
17
|
const cwd = process.cwd();
|
|
18
|
-
const check = !!options.check;
|
|
19
18
|
const legacyAgentDir = path.join(cwd, '.agent');
|
|
20
19
|
const { version } = require(path.join(__dirname, '..', 'package.json'));
|
|
21
20
|
const installState = await detectInstallState(cwd);
|
|
22
21
|
const legacyAgentExists = await pathExists(legacyAgentDir);
|
|
23
22
|
const isLegacyMigration = installState.selectedTargets.length === 0 && legacyAgentExists;
|
|
24
|
-
const
|
|
25
|
-
const targetPlans = buildProjectionPlan(selectedTargetIds);
|
|
23
|
+
const detectedTargetIds = isLegacyMigration ? ['antigravity'] : installState.selectedTargets;
|
|
26
24
|
|
|
27
|
-
if (
|
|
25
|
+
if (detectedTargetIds.length === 0 && !legacyAgentExists) {
|
|
28
26
|
logo();
|
|
29
27
|
error('No supported Anws target layout found in current directory.');
|
|
30
28
|
info('Run `anws init` first to set up the workflow system.');
|
|
31
29
|
process.exit(1);
|
|
32
30
|
}
|
|
33
31
|
|
|
32
|
+
const targetPlans = buildProjectionPlan(detectedTargetIds);
|
|
33
|
+
const detectedTargetPlans = buildProjectionPlan(detectedTargetIds);
|
|
34
|
+
|
|
34
35
|
const srcAgents = ROOT_AGENTS_FILE;
|
|
35
36
|
|
|
36
37
|
if (isLegacyMigration) {
|
|
@@ -100,41 +101,18 @@ async function update(options = {}) {
|
|
|
100
101
|
|
|
101
102
|
const changes = targetContexts.flatMap((context) => context.changes);
|
|
102
103
|
|
|
103
|
-
if (check) {
|
|
104
|
-
if (!versionState.needUpgrade) {
|
|
105
|
-
if (!isLegacyMigration) {
|
|
106
|
-
logo();
|
|
107
|
-
blank();
|
|
108
|
-
}
|
|
109
|
-
info(`Already up to date. Latest recorded version is v${versionState.latestVersion || version}.`);
|
|
110
|
-
printTargetSelection(installState, targetContexts.map((context) => context.target));
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
if (!isLegacyMigration) {
|
|
114
|
-
logo();
|
|
115
|
-
blank();
|
|
116
|
-
}
|
|
117
|
-
printTargetSelection(installState, targetContexts.map((context) => context.target));
|
|
118
|
-
printPreview({
|
|
119
|
-
fromVersion: versionState.fromVersion,
|
|
120
|
-
toVersion: versionState.toVersion,
|
|
121
|
-
changes
|
|
122
|
-
});
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
104
|
if (!versionState.needUpgrade) {
|
|
127
105
|
if (!isLegacyMigration) {
|
|
128
106
|
logo();
|
|
129
107
|
blank();
|
|
130
108
|
}
|
|
131
109
|
printTargetSelection(installState, targetContexts.map((context) => context.target));
|
|
132
|
-
if (
|
|
110
|
+
if (installState.canRebuildLock && detectedTargetIds.length > 0) {
|
|
133
111
|
const generatedAt = new Date().toISOString();
|
|
134
112
|
await writeInstallLock(cwd, createInstallLock({
|
|
135
113
|
cliVersion: version,
|
|
136
114
|
generatedAt,
|
|
137
|
-
targets: dedupeTargets(
|
|
115
|
+
targets: dedupeTargets(detectedTargetPlans.map((targetPlan) => summarizeTargetState(targetPlan, version))),
|
|
138
116
|
lastUpdateSummary: {
|
|
139
117
|
successfulTargets: [],
|
|
140
118
|
failedTargets: [],
|
|
@@ -152,15 +130,7 @@ async function update(options = {}) {
|
|
|
152
130
|
blank();
|
|
153
131
|
}
|
|
154
132
|
|
|
155
|
-
|
|
156
|
-
installState,
|
|
157
|
-
targets: targetContexts.map((context) => context.target)
|
|
158
|
-
});
|
|
159
|
-
if (!confirmed) {
|
|
160
|
-
blank();
|
|
161
|
-
info('Aborted. No files were changed.');
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
133
|
+
printTargetSelection(installState, targetContexts.map((context) => context.target));
|
|
164
134
|
|
|
165
135
|
const updated = [];
|
|
166
136
|
const skipped = [];
|
|
@@ -217,6 +187,12 @@ async function update(options = {}) {
|
|
|
217
187
|
}
|
|
218
188
|
});
|
|
219
189
|
const generatedAt = new Date().toISOString();
|
|
190
|
+
const successfulTargetIdSet = new Set(successfulTargets.map((item) => item.targetId));
|
|
191
|
+
const retainedDetectedTargets = installState.canRebuildLock
|
|
192
|
+
? detectedTargetPlans
|
|
193
|
+
.filter((targetPlan) => !successfulTargetIdSet.has(targetPlan.targetId))
|
|
194
|
+
.map((targetPlan) => summarizeTargetState(targetPlan, version))
|
|
195
|
+
: [];
|
|
220
196
|
const existingLockTargets = installState.canRebuildLock
|
|
221
197
|
? []
|
|
222
198
|
: (installState.lockResult.lock?.targets || []);
|
|
@@ -225,6 +201,7 @@ async function update(options = {}) {
|
|
|
225
201
|
generatedAt,
|
|
226
202
|
targets: dedupeTargets([
|
|
227
203
|
...existingLockTargets,
|
|
204
|
+
...retainedDetectedTargets,
|
|
228
205
|
...successfulTargets
|
|
229
206
|
]),
|
|
230
207
|
lastUpdateSummary: {
|
|
@@ -251,23 +228,6 @@ async function update(options = {}) {
|
|
|
251
228
|
});
|
|
252
229
|
}
|
|
253
230
|
|
|
254
|
-
async function askUpdate({ installState, targets }) {
|
|
255
|
-
if (global.__ANWS_FORCE_YES) return true;
|
|
256
|
-
|
|
257
|
-
if (!process.stdin.isTTY) {
|
|
258
|
-
warn('Non-TTY environment detected. Skipping update to avoid accidental overwrites.');
|
|
259
|
-
return false;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
return confirm({
|
|
263
|
-
message: buildUpdateConfirmationMessage(targets),
|
|
264
|
-
contextLines: buildUpdateConfirmationContextLines(installState, targets),
|
|
265
|
-
confirmLabel: 'Continue',
|
|
266
|
-
cancelLabel: 'Cancel',
|
|
267
|
-
defaultValue: false
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
|
|
271
231
|
async function askMigrate() {
|
|
272
232
|
if (global.__ANWS_FORCE_YES) return true;
|
|
273
233
|
|
|
@@ -308,23 +268,8 @@ async function maybeDeleteLegacyDir(legacyAgentDir) {
|
|
|
308
268
|
return true;
|
|
309
269
|
}
|
|
310
270
|
|
|
311
|
-
function
|
|
312
|
-
|
|
313
|
-
if (labels.length === 0) {
|
|
314
|
-
return 'This will overwrite all managed files for the detected target layout.';
|
|
315
|
-
}
|
|
316
|
-
return `This will overwrite all managed files for: ${labels.join(', ')}.`;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
function buildUpdateConfirmationContextLines(installState, targets) {
|
|
320
|
-
const lines = [
|
|
321
|
-
`Matched targets: ${targets.map((target) => `${target.label} (${target.id})`).join(', ') || 'none'}`,
|
|
322
|
-
installState.needsFallback ? 'State source: directory scan fallback' : 'State source: install-lock + directory scan'
|
|
323
|
-
];
|
|
324
|
-
if (installState.drift.hasDrift) {
|
|
325
|
-
lines.push(`State drift detected. Missing on disk: ${installState.drift.missingOnDisk.join(', ') || 'none'}; untracked on disk: ${installState.drift.untrackedOnDisk.join(', ') || 'none'}.`);
|
|
326
|
-
}
|
|
327
|
-
return lines;
|
|
271
|
+
function buildSelectionModeLine() {
|
|
272
|
+
return 'Selection mode: detected target layout';
|
|
328
273
|
}
|
|
329
274
|
|
|
330
275
|
function printLegacyMigrationNotice() {
|
|
@@ -338,6 +283,7 @@ function printLegacyMigrationNotice() {
|
|
|
338
283
|
function printTargetSelection(installState, targets) {
|
|
339
284
|
blank();
|
|
340
285
|
section('Target selection', [
|
|
286
|
+
buildSelectionModeLine(),
|
|
341
287
|
`Matched targets: ${targets.map((target) => `${target.label} (${target.id})`).join(', ') || 'none'}`,
|
|
342
288
|
installState.needsFallback ? 'State source: directory scan fallback' : 'State source: install-lock + directory scan',
|
|
343
289
|
...(installState.drift.hasDrift
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@haaaiawd/anws",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "Anws — A spec-driven workflow framework for AI-assisted development. Empowers prompt engineers to build production-ready software through structured PRD → Architecture → Task decomposition. Works with Claude Code, GitHub Copilot, Cursor, Windsurf, and any tool that reads AGENTS.md.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"anws",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: design-reviewer
|
|
3
|
-
description:
|
|
3
|
+
description: 使用三维框架(系统设计、运行模拟、工程实现)系统性审查架构和系统设计文档,作为 challenge 工作流中的规范契约设计证据层。产出按严重度分级的发现,关联到具体文档段落。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# 设计审查大师手册
|
|
@@ -9,6 +9,8 @@ description: 使用三维框架(系统设计、运行模拟、工程实现)
|
|
|
9
9
|
> 对设计严厉,代码才能优雅。"
|
|
10
10
|
|
|
11
11
|
你是**设计审查大师**,负责系统性审查架构和系统设计文档。你的三维框架确保没有任何一类风险被遗漏。
|
|
12
|
+
在 `/challenge` 工作流中,你的角色是:**为规范契约是否闭合提供设计侧证据**,而不是单独给出脱离上下文的最终裁决。
|
|
13
|
+
你优先要证明的是:哪些契约在**系统边界、接口、状态、时序、错误路径**上没有闭合。
|
|
12
14
|
|
|
13
15
|
---
|
|
14
16
|
|
|
@@ -126,15 +128,28 @@ description: 使用三维框架(系统设计、运行模拟、工程实现)
|
|
|
126
128
|
| 工程实现 | — | — | — | — | — |
|
|
127
129
|
| **合计** | **—** | **—** | **—** | **—** | **—** |
|
|
128
130
|
|
|
131
|
+
**高信号结论**: [用 1-3 句概括最值得进入 challenge 主报告的问题]
|
|
132
|
+
|
|
129
133
|
---
|
|
130
134
|
|
|
131
|
-
###
|
|
135
|
+
### 核心发现清单
|
|
132
136
|
|
|
133
|
-
|
|
134
|
-
|
|
137
|
+
| ID | 维度 | 严重度 | 文档位置 | 发现 | 影响 | 建议 |
|
|
138
|
+
|----|------|--------|----------|------|------|------|
|
|
139
|
+
| DR-01 | 系统设计 | Critical | 02_ARCHITECTURE_OVERVIEW.md §X | 边界定义冲突,两个系统职责重叠 | 实现阶段职责漂移、返工风险高 | 重新划清系统边界并更新引用 |
|
|
140
|
+
| DR-02 | 运行模拟 | High | 04_SYSTEM_DESIGN/... §Y | 故障传播路径未定义 | 级联失败时无法收敛 | 增加超时/降级/重试策略 |
|
|
141
|
+
| DR-03 | 工程实现 | Medium | ADR-00X / System Design §Z | 可测试接缝不足 | 后续验证成本高 | 增加接口隔离或 mock 接缝 |
|
|
142
|
+
|
|
143
|
+
> 仅输出真正影响设计判断的问题。低价值措辞、重复担忧不要进入清单。
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
### Top Findings 详情(仅展开 Critical / High)
|
|
135
148
|
|
|
136
|
-
|
|
137
|
-
|
|
149
|
+
#### DR-01 [标题]
|
|
150
|
+
|
|
151
|
+
**严重度**: Critical
|
|
152
|
+
**文档位置**: [精确的文件和章节引用]
|
|
138
153
|
|
|
139
154
|
**证据**:
|
|
140
155
|
- 文档分析: [来自 PRD/Architecture/ADR 的具体内容]
|
|
@@ -145,7 +160,7 @@ description: 使用三维框架(系统设计、运行模拟、工程实现)
|
|
|
145
160
|
- [不修复会发生什么]
|
|
146
161
|
|
|
147
162
|
**建议**:
|
|
148
|
-
[
|
|
163
|
+
- [最小修复方向]
|
|
149
164
|
```
|
|
150
165
|
|
|
151
166
|
---
|
|
@@ -537,14 +537,31 @@ classDiagram
|
|
|
537
537
|
- **RBAC (Role-Based Access Control)**: 基于角色的访问控制
|
|
538
538
|
- **p95**: 95th percentile,95%的请求响应时间小于该值
|
|
539
539
|
|
|
540
|
-
### 14.2
|
|
540
|
+
### 14.2 Optional Skills & Reference Resources (可选 Skills 与参考资源)
|
|
541
|
+
>
|
|
542
|
+
> 本节用于记录在设计过程中实际参考过的 skill、组件库、方法论或外部资料。
|
|
543
|
+
> 这些内容是辅助输入,不是系统事实来源;最终方案仍以本项目的 PRD、ADR、Architecture Overview 和本文档自身为准。
|
|
544
|
+
>
|
|
545
|
+
> **记录建议**:
|
|
546
|
+
> - 写明资源名称
|
|
547
|
+
> - 写明它帮助了哪个设计决策
|
|
548
|
+
> - 写明最终采纳了什么,舍弃了什么
|
|
549
|
+
>
|
|
550
|
+
> **示例(前端系统)**:
|
|
551
|
+
> - `vercel-react-best-practices`: 用于校验 React 组件边界、渲染策略、性能优化建议
|
|
552
|
+
> - `frontend-design`: 用于参考排版、配色、层级和动效方向
|
|
553
|
+
> - `shadcn/ui`: 用于基础组件模式参考
|
|
554
|
+
> - `Aceternity UI`: 用于展示型区块和交互动效灵感
|
|
555
|
+
> - `Magic UI`: 用于 Tailwind-first 的视觉与动画参考
|
|
556
|
+
|
|
557
|
+
### 14.3 References (参考资料)
|
|
541
558
|
- [FastAPI Documentation](https://fastapi.tiangolo.com/)
|
|
542
559
|
- [PostgreSQL Best Practices](https://wiki.postgresql.org/wiki/Don%27t_Do_This)
|
|
543
560
|
- [JWT Best Practices](https://tools.ietf.org/html/rfc8725)
|
|
544
561
|
- [Architecture Overview](../02_ARCHITECTURE_OVERVIEW.md)
|
|
545
562
|
- [ADR001: Tech Stack](../03_ADR/ADR001_TECH_STACK.md)
|
|
546
563
|
|
|
547
|
-
### 14.
|
|
564
|
+
### 14.4 Change Log (变更日志)
|
|
548
565
|
|
|
549
566
|
| Version | Date | Changes | Author |
|
|
550
567
|
| ------- | ---------- | -------- | ------ |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: task-reviewer
|
|
3
|
-
description: 系统性审查 05_TASKS.md
|
|
3
|
+
description: 系统性审查 05_TASKS.md 的质量与完备性,作为 challenge 工作流中的规范契约任务承接证据层。通过 6 大检测 Pass 在语义模型上运行,检测重复、歧义、欠详述、不一致、覆盖缺口和质量问题。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# 任务审查大师手册
|
|
@@ -9,10 +9,11 @@ description: 系统性审查 05_TASKS.md 的质量与完备性。通过 6 大检
|
|
|
9
9
|
> 在代码暴露问题之前,找到裂缝。"
|
|
10
10
|
|
|
11
11
|
你是**任务审查大师**,负责对 `05_TASKS.md` 进行系统性审计——以 PRD、Architecture 和 ADR 文档为基准,运行 **6 大检测 Pass**。你的武器是**语义模型**,而非朴素的字符串匹配。
|
|
12
|
+
在 `/challenge` 工作流中,你的角色是:**为规范契约是否被任务承接、覆盖和验证提供证据**,而不是单独替代 challenge 的总判断。
|
|
13
|
+
你优先要证明的是:关键承诺是否有实现任务、验证任务、边界/失败路径任务,以及是否存在幽灵任务稀释主轴。
|
|
12
14
|
|
|
13
15
|
---
|
|
14
|
-
|
|
15
|
-
## ⚡ 任务目标
|
|
16
|
+
## 任务目标
|
|
16
17
|
|
|
17
18
|
1. **加载文档 (必须)**: 读取 `.anws/v{N}/05_TASKS.md`、`01_PRD.md`、`02_ARCHITECTURE_OVERVIEW.md` 以及所有 `03_ADR/*.md`。
|
|
18
19
|
2. **构建语义模型**: 构建 3 个清单模型(见 §语义模型构建)。
|
|
@@ -21,7 +22,7 @@ description: 系统性审查 05_TASKS.md 的质量与完备性。通过 6 大检
|
|
|
21
22
|
5. **生成报告**: 输出任务审查报告(见 §输出格式)。
|
|
22
23
|
6. **展示摘要**: 向用户展示检测汇总表 + 前 10 条发现。
|
|
23
24
|
|
|
24
|
-
##
|
|
25
|
+
## 硬约束
|
|
25
26
|
|
|
26
27
|
- **发现上限**: 最多 50 条。超出时按严重度排序 → 截断 → 追加溢出摘要。
|
|
27
28
|
- **只报告不修复**: 本技能**仅输出报告**。修复由用户或其他工作流完成。
|
|
@@ -29,8 +30,7 @@ description: 系统性审查 05_TASKS.md 的质量与完备性。通过 6 大检
|
|
|
29
30
|
- **客观性**: 仅标记客观可检测的问题。不要为了填满报告而捏造问题。
|
|
30
31
|
|
|
31
32
|
---
|
|
32
|
-
|
|
33
|
-
## 🧠 语义模型构建
|
|
33
|
+
## 语义模型构建
|
|
34
34
|
|
|
35
35
|
> 在执行任何 Pass 之前,先构建以下 3 个模型。所有 Pass 在模型上操作,而非原始文本。
|
|
36
36
|
|
|
@@ -206,6 +206,8 @@ T{X.Y.Z}: 标题
|
|
|
206
206
|
|
|
207
207
|
**整体健康度**: 🟢 健康 / 🟡 需关注 / 🔴 阻塞
|
|
208
208
|
|
|
209
|
+
**高信号结论**: [用 1-3 句概括最值得进入 challenge 主报告的问题]
|
|
210
|
+
|
|
209
211
|
---
|
|
210
212
|
|
|
211
213
|
### REQ 覆盖率
|
|
@@ -248,14 +250,36 @@ graph LR
|
|
|
248
250
|
|
|
249
251
|
---
|
|
250
252
|
|
|
251
|
-
###
|
|
253
|
+
### 核心发现清单
|
|
254
|
+
|
|
255
|
+
| ID | 严重度 | Pass | 位置 | 发现 | 影响 | 建议 |
|
|
256
|
+
|----|:------:|:----:|------|------|------|------|
|
|
257
|
+
| TR-01 | CRITICAL | E1 | REQ-003 / 05_TASKS.md §X | P0 需求无对应任务 | 核心能力无法落地 | 在对应 Sprint 增加实现与验证任务 |
|
|
258
|
+
| TR-02 | HIGH | B1 | T4.1.3 | 验收标准使用“正确处理”等模糊措辞 | 任务不可验证 | 量化错误码、兜底行为和验证方式 |
|
|
259
|
+
| TR-03 | HIGH | D1 | PRD / Architecture / Tasks | 术语漂移导致任务引用不一致 | 实施与对齐成本上升 | 按 ADR 统一术语 |
|
|
252
260
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
261
|
+
> 仅输出真正影响执行和验收的问题。低价值措辞润色不要淹没核心发现。
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
### Top Findings 详情(仅展开 Critical / High)
|
|
266
|
+
|
|
267
|
+
#### TR-01 [标题]
|
|
268
|
+
|
|
269
|
+
**Pass**: E1
|
|
270
|
+
**严重度**: CRITICAL
|
|
271
|
+
**位置**: [REQ-ID / Task ID / 文档章节]
|
|
272
|
+
|
|
273
|
+
**证据**:
|
|
274
|
+
- 需求来源: [PRD 中的 REQ / US]
|
|
275
|
+
- 任务映射: [哪些任务缺失 / 不完整]
|
|
276
|
+
- 交叉验证: [与 Architecture / ADR 的不一致点,如适用]
|
|
277
|
+
|
|
278
|
+
**影响**:
|
|
279
|
+
- [不修复会导致什么执行或交付问题]
|
|
280
|
+
|
|
281
|
+
**建议**:
|
|
282
|
+
- [最小修复方向]
|
|
259
283
|
|
|
260
284
|
---
|
|
261
285
|
|
|
@@ -268,14 +292,17 @@ graph LR
|
|
|
268
292
|
|
|
269
293
|
## 🎚️ 严重度分级
|
|
270
294
|
|
|
271
|
-
| 等级 | 判定标准 |
|
|
295
|
+
| 等级 | 判定标准 | 所需行动 |
|
|
272
296
|
|:----:|---------|---------|
|
|
273
|
-
| **
|
|
274
|
-
| **
|
|
275
|
-
| **
|
|
276
|
-
| **
|
|
297
|
+
| **Critical** 🔴 | 根本性矛盾或不可能实现。不解决无法继续。 | P0 — 必须在 blueprint/forge 之前修复 |
|
|
298
|
+
| **High** 🟠 | 大概率导致返工或失败的严重风险。 | P1 — 在 forge 之前修复 |
|
|
299
|
+
| **Medium** 🟡 | 有变通方案的质量隐患。 | P2 — 实现阶段修复 |
|
|
300
|
+
| **Low** 🟢 | 润色项或轻微不一致。 | P3 — 后续跟踪 |
|
|
301
|
+
|
|
302
|
+
**健康度规则**: Critical ≥ 1 → 整体健康度设为 🔴 阻塞。High ≥ 5 → 🟡 需关注。其余 → 🟢 健康。
|
|
277
303
|
|
|
278
|
-
|
|
304
|
+
> [!NOTE]
|
|
305
|
+
> 输出时优先保留 Critical / High。Medium / Low 仅在确实影响执行判断或有稳定改进价值时保留。
|
|
279
306
|
|
|
280
307
|
---
|
|
281
308
|
|