@haaaiawd/anws 2.2.0 → 2.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +180 -343
- package/bin/cli.js +112 -112
- package/lib/changelog.js +258 -258
- package/lib/copy.js +116 -109
- package/lib/diff.js +11 -0
- package/lib/manifest.js +4 -1
- package/lib/update.js +319 -319
- package/package.json +4 -3
- package/templates/.agents/skills/anws-system/SKILL.md +9 -7
- package/templates/.agents/skills/code-reviewer/SKILL.md +102 -327
- package/templates/.agents/skills/concept-modeler/SKILL.md +19 -17
- package/templates/.agents/skills/craft-authoring/SKILL.md +123 -0
- package/templates/.agents/skills/e2e-testing-guide/SKILL.md +59 -0
- package/templates/.agents/skills/system-designer/SKILL.md +6 -6
- package/templates/.agents/skills/system-designer/references/system-design-template.md +17 -17
- package/templates/.agents/skills/task-planner/SKILL.md +113 -113
- package/templates/.agents/skills/task-planner/references/TASK_TEMPLATE.md +82 -82
- package/templates/.agents/workflows/blueprint.md +284 -284
- package/templates/.agents/workflows/challenge.md +450 -491
- package/templates/.agents/workflows/change.md +263 -286
- package/templates/.agents/workflows/craft.md +243 -664
- package/templates/.agents/workflows/design-system.md +624 -624
- package/templates/.agents/workflows/explore.md +400 -371
- package/templates/.agents/workflows/forge.md +444 -413
- package/templates/.agents/workflows/genesis.md +342 -395
- package/templates/.agents/workflows/probe.md +21 -16
- package/templates/.agents/workflows/quickstart.md +123 -138
- package/templates/AGENTS.md +149 -134
package/lib/update.js
CHANGED
|
@@ -1,319 +1,319 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const fs = require('node:fs/promises');
|
|
4
|
-
const path = require('node:path');
|
|
5
|
-
const { buildProjectionPlan } = require('./manifest');
|
|
6
|
-
const { getTarget } = require('./adapters');
|
|
7
|
-
const { planAgentsUpdate, resolveAgentsInstall, printLegacyMigrationWarning, pathExists } = require('./agents');
|
|
8
|
-
const { collectManagedFileDiffs } = require('./diff');
|
|
9
|
-
const { detectUpgrade, generateChangelog } = require('./changelog');
|
|
10
|
-
const { writeTargetFiles } = require('./copy');
|
|
11
|
-
const { createInstallLock, dedupeTargets, detectInstallState, summarizeTargetState, writeInstallLock } = require('./install-state');
|
|
12
|
-
const { confirm } = require('./prompt');
|
|
13
|
-
const { ROOT_AGENTS_FILE, resolveCanonicalSource } = require('./resources');
|
|
14
|
-
const { warn, error, info, fileLine, skippedLine, blank, logo, section } = require('./output');
|
|
15
|
-
|
|
16
|
-
async function update() {
|
|
17
|
-
const cwd = process.cwd();
|
|
18
|
-
const legacyAgentDir = path.join(cwd, '.agent');
|
|
19
|
-
const { version } = require(path.join(__dirname, '..', 'package.json'));
|
|
20
|
-
const installState = await detectInstallState(cwd);
|
|
21
|
-
const legacyAgentExists = await pathExists(legacyAgentDir);
|
|
22
|
-
const isLegacyMigration = installState.selectedTargets.length === 0 && legacyAgentExists;
|
|
23
|
-
const detectedTargetIds = isLegacyMigration ? ['antigravity'] : installState.selectedTargets;
|
|
24
|
-
|
|
25
|
-
if (detectedTargetIds.length === 0 && !legacyAgentExists) {
|
|
26
|
-
logo();
|
|
27
|
-
error('No supported Anws target layout found in current directory.');
|
|
28
|
-
info('Run `anws init` first to set up the workflow system.');
|
|
29
|
-
process.exit(1);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const targetPlans = buildProjectionPlan(detectedTargetIds);
|
|
33
|
-
const detectedTargetPlans = buildProjectionPlan(detectedTargetIds);
|
|
34
|
-
|
|
35
|
-
const srcAgents = ROOT_AGENTS_FILE;
|
|
36
|
-
|
|
37
|
-
if (isLegacyMigration) {
|
|
38
|
-
logo();
|
|
39
|
-
blank();
|
|
40
|
-
printLegacyMigrationNotice();
|
|
41
|
-
blank();
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const versionState = await detectUpgrade({ cwd, version });
|
|
45
|
-
const targetContexts = [];
|
|
46
|
-
|
|
47
|
-
for (const targetPlan of targetPlans) {
|
|
48
|
-
const target = getTarget(targetPlan.targetId);
|
|
49
|
-
const agentsDecision = target.id === 'antigravity'
|
|
50
|
-
? await resolveAgentsInstall({
|
|
51
|
-
cwd,
|
|
52
|
-
askMigrate,
|
|
53
|
-
forceYes: !!global.__ANWS_FORCE_YES
|
|
54
|
-
})
|
|
55
|
-
: {
|
|
56
|
-
shouldWriteRootAgents: false,
|
|
57
|
-
shouldWarnMigration: false,
|
|
58
|
-
rootExists: false,
|
|
59
|
-
legacyExists: false
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
if (!agentsDecision.shouldWriteRootAgents && agentsDecision.legacyExists) {
|
|
63
|
-
info('Keeping legacy .agent/rules/agents.md. Will not pull root AGENTS.md.');
|
|
64
|
-
}
|
|
65
|
-
if (agentsDecision.shouldWarnMigration) {
|
|
66
|
-
printLegacyMigrationWarning();
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
let agentsUpdatePlan = null;
|
|
70
|
-
if (agentsDecision.shouldWriteRootAgents && agentsDecision.rootExists) {
|
|
71
|
-
const templateContent = await fs.readFile(srcAgents, 'utf8');
|
|
72
|
-
const existingContent = await fs.readFile(path.join(cwd, 'AGENTS.md'), 'utf8');
|
|
73
|
-
agentsUpdatePlan = planAgentsUpdate({ templateContent, existingContent });
|
|
74
|
-
|
|
75
|
-
if (agentsUpdatePlan.warning) {
|
|
76
|
-
warn(agentsUpdatePlan.warning);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const rawChanges = await collectManagedFileDiffs({
|
|
81
|
-
cwd,
|
|
82
|
-
projectionPlan: [targetPlan],
|
|
83
|
-
srcAgents,
|
|
84
|
-
shouldWriteRootAgents: agentsDecision.shouldWriteRootAgents,
|
|
85
|
-
agentsUpdatePlan
|
|
86
|
-
});
|
|
87
|
-
const changes = rawChanges.filter((item) => {
|
|
88
|
-
if (item.file !== 'AGENTS.md') return true;
|
|
89
|
-
if (agentsUpdatePlan && agentsUpdatePlan.mode === 'skip') return false;
|
|
90
|
-
return agentsDecision.shouldWriteRootAgents;
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
targetContexts.push({
|
|
94
|
-
target,
|
|
95
|
-
targetPlan,
|
|
96
|
-
agentsDecision,
|
|
97
|
-
agentsUpdatePlan,
|
|
98
|
-
changes
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const changes = targetContexts.flatMap((context) => context.changes);
|
|
103
|
-
|
|
104
|
-
if (!versionState.needUpgrade) {
|
|
105
|
-
if (!isLegacyMigration) {
|
|
106
|
-
logo();
|
|
107
|
-
blank();
|
|
108
|
-
}
|
|
109
|
-
printTargetSelection(installState, targetContexts.map((context) => context.target));
|
|
110
|
-
if (installState.canRebuildLock && detectedTargetIds.length > 0) {
|
|
111
|
-
const generatedAt = new Date().toISOString();
|
|
112
|
-
await writeInstallLock(cwd, createInstallLock({
|
|
113
|
-
cliVersion: version,
|
|
114
|
-
generatedAt,
|
|
115
|
-
targets: dedupeTargets(detectedTargetPlans.map((targetPlan) => summarizeTargetState(targetPlan, version))),
|
|
116
|
-
lastUpdateSummary: {
|
|
117
|
-
successfulTargets: [],
|
|
118
|
-
failedTargets: [],
|
|
119
|
-
updatedAt: generatedAt
|
|
120
|
-
}
|
|
121
|
-
}));
|
|
122
|
-
info('Rebuilt .anws/install-lock.json from the detected target layout.');
|
|
123
|
-
}
|
|
124
|
-
info(`Already up to date. Latest recorded version is v${versionState.latestVersion || version}.`);
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
if (!isLegacyMigration) {
|
|
129
|
-
logo();
|
|
130
|
-
blank();
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
printTargetSelection(installState, targetContexts.map((context) => context.target));
|
|
134
|
-
|
|
135
|
-
const updated = [];
|
|
136
|
-
const skipped = [];
|
|
137
|
-
const successfulTargets = [];
|
|
138
|
-
const failedTargets = [];
|
|
139
|
-
|
|
140
|
-
for (const context of targetContexts) {
|
|
141
|
-
try {
|
|
142
|
-
const result = await writeTargetFiles(cwd, {
|
|
143
|
-
targetPlan: context.targetPlan,
|
|
144
|
-
protectedFiles: context.targetPlan.userProtectedFiles,
|
|
145
|
-
srcAgents,
|
|
146
|
-
shouldWriteRootAgents: context.agentsDecision.shouldWriteRootAgents,
|
|
147
|
-
agentsUpdatePlan: context.agentsUpdatePlan,
|
|
148
|
-
resolveCanonicalSource
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
updated.push(...result.written);
|
|
152
|
-
skipped.push(...result.skipped);
|
|
153
|
-
successfulTargets.push(summarizeTargetState(context.targetPlan, version));
|
|
154
|
-
} catch (error) {
|
|
155
|
-
failedTargets.push({
|
|
156
|
-
targetId: context.target.id,
|
|
157
|
-
targetLabel: context.target.label,
|
|
158
|
-
reason: error.message
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
blank();
|
|
164
|
-
info('Updated files:');
|
|
165
|
-
blank();
|
|
166
|
-
for (const rel of updated) {
|
|
167
|
-
fileLine(rel.replace(/\\/g, '/'));
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
if (skipped.length > 0) {
|
|
171
|
-
blank();
|
|
172
|
-
info('Skipped (project-specific, preserved):');
|
|
173
|
-
for (const rel of skipped) {
|
|
174
|
-
skippedLine(rel.replace(/\\/g, '/'));
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
printTargetUpdateSummary(successfulTargets, failedTargets);
|
|
179
|
-
|
|
180
|
-
const changelogPath = await generateChangelog({
|
|
181
|
-
cwd,
|
|
182
|
-
version,
|
|
183
|
-
changes,
|
|
184
|
-
targetSummary: {
|
|
185
|
-
successfulTargets: successfulTargets.map((item) => `${item.targetLabel} (${item.targetId})`),
|
|
186
|
-
failedTargets: failedTargets.map((item) => `${item.targetLabel} (${item.targetId})`)
|
|
187
|
-
}
|
|
188
|
-
});
|
|
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
|
-
: [];
|
|
196
|
-
const existingLockTargets = installState.canRebuildLock
|
|
197
|
-
? []
|
|
198
|
-
: (installState.lockResult.lock?.targets || []);
|
|
199
|
-
await writeInstallLock(cwd, createInstallLock({
|
|
200
|
-
cliVersion: version,
|
|
201
|
-
generatedAt,
|
|
202
|
-
targets: dedupeTargets([
|
|
203
|
-
...existingLockTargets,
|
|
204
|
-
...retainedDetectedTargets,
|
|
205
|
-
...successfulTargets
|
|
206
|
-
]),
|
|
207
|
-
lastUpdateSummary: {
|
|
208
|
-
successfulTargets: successfulTargets.map((item) => item.targetId),
|
|
209
|
-
failedTargets: failedTargets.map((item) => item.targetId),
|
|
210
|
-
updatedAt: generatedAt
|
|
211
|
-
}
|
|
212
|
-
}));
|
|
213
|
-
|
|
214
|
-
let legacyCleanupLine = '';
|
|
215
|
-
if (isLegacyMigration) {
|
|
216
|
-
legacyCleanupLine = 'Legacy .agent/ was preserved. You can review and delete it manually after migration.';
|
|
217
|
-
const deleted = await maybeDeleteLegacyDir(legacyAgentDir);
|
|
218
|
-
if (deleted) {
|
|
219
|
-
legacyCleanupLine = 'Legacy .agent/ directory was deleted after confirmation.';
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
printUpdateCompletionSummary({
|
|
224
|
-
updatedCount: updated.length,
|
|
225
|
-
skippedCount: skipped.length,
|
|
226
|
-
changelogPath: path.relative(cwd, changelogPath).replace(/\\/g, '/'),
|
|
227
|
-
legacyCleanupLine
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
async function askMigrate() {
|
|
232
|
-
if (global.__ANWS_FORCE_YES) return true;
|
|
233
|
-
|
|
234
|
-
if (!process.stdin.isTTY) {
|
|
235
|
-
return false;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
return confirm({
|
|
239
|
-
message: 'Legacy .agent/ directory detected. Migrate to .agents/?',
|
|
240
|
-
confirmLabel: 'Migrate',
|
|
241
|
-
cancelLabel: 'Keep legacy',
|
|
242
|
-
defaultValue: false
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
async function maybeDeleteLegacyDir(legacyAgentDir) {
|
|
247
|
-
const exists = await pathExists(legacyAgentDir);
|
|
248
|
-
if (!exists) return false;
|
|
249
|
-
|
|
250
|
-
if (global.__ANWS_FORCE_YES) {
|
|
251
|
-
return false;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
if (!process.stdin.isTTY) {
|
|
255
|
-
return false;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
const shouldDelete = await confirm({
|
|
259
|
-
message: 'Legacy .agent/ directory has been preserved. Delete it now?',
|
|
260
|
-
confirmLabel: 'Delete',
|
|
261
|
-
cancelLabel: 'Keep',
|
|
262
|
-
defaultValue: false
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
if (!shouldDelete) return false;
|
|
266
|
-
|
|
267
|
-
await fs.rm(legacyAgentDir, { recursive: true, force: true });
|
|
268
|
-
return true;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
function buildSelectionModeLine() {
|
|
272
|
-
return 'Selection mode: detected target layout';
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
function printLegacyMigrationNotice() {
|
|
276
|
-
section('Legacy migration', [
|
|
277
|
-
'Legacy .agent/ directory detected.',
|
|
278
|
-
'anws update will migrate managed files into the Antigravity target structure.',
|
|
279
|
-
'Your old .agent/ directory will be preserved for manual review.'
|
|
280
|
-
], { minWidth: 60 });
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
function printTargetSelection(installState, targets) {
|
|
284
|
-
blank();
|
|
285
|
-
section('Target selection', [
|
|
286
|
-
buildSelectionModeLine(),
|
|
287
|
-
`Matched targets: ${targets.map((target) => `${target.label} (${target.id})`).join(', ') || 'none'}`,
|
|
288
|
-
installState.needsFallback ? 'State source: directory scan fallback' : 'State source: install-lock + directory scan',
|
|
289
|
-
...(installState.drift.hasDrift
|
|
290
|
-
? [`State drift detected. Missing on disk: ${installState.drift.missingOnDisk.join(', ') || 'none'}; untracked on disk: ${installState.drift.untrackedOnDisk.join(', ') || 'none'}.`]
|
|
291
|
-
: [])
|
|
292
|
-
]);
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
function printTargetUpdateSummary(successfulTargets, failedTargets) {
|
|
296
|
-
blank();
|
|
297
|
-
section('Update summary by target', [
|
|
298
|
-
...successfulTargets.map((target) => `✔ ${target.targetLabel} (${target.targetId})`),
|
|
299
|
-
...failedTargets.map((target) => `✖ ${target.targetLabel} (${target.targetId}) — ${target.reason}`)
|
|
300
|
-
]);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
function printUpdateCompletionSummary({ updatedCount, skippedCount, changelogPath, legacyCleanupLine }) {
|
|
304
|
-
blank();
|
|
305
|
-
section('Update completed', [
|
|
306
|
-
`✔ Done! ${updatedCount} file(s) updated${skippedCount > 0 ? `, ${skippedCount} skipped` : ''}.`,
|
|
307
|
-
'Managed files have been updated to the latest version.',
|
|
308
|
-
'Your custom files outside the selected target projections were not touched.',
|
|
309
|
-
...(legacyCleanupLine ? [legacyCleanupLine] : []),
|
|
310
|
-
`Generated upgrade record: ${changelogPath}`,
|
|
311
|
-
'Run `/upgrade` in your AI IDE to update your architecture docs.'
|
|
312
|
-
], { minWidth: 60 });
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
module.exports = update;
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs/promises');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
const { buildProjectionPlan } = require('./manifest');
|
|
6
|
+
const { getTarget } = require('./adapters');
|
|
7
|
+
const { planAgentsUpdate, resolveAgentsInstall, printLegacyMigrationWarning, pathExists } = require('./agents');
|
|
8
|
+
const { collectManagedFileDiffs } = require('./diff');
|
|
9
|
+
const { detectUpgrade, generateChangelog } = require('./changelog');
|
|
10
|
+
const { writeTargetFiles } = require('./copy');
|
|
11
|
+
const { createInstallLock, dedupeTargets, detectInstallState, summarizeTargetState, writeInstallLock } = require('./install-state');
|
|
12
|
+
const { confirm } = require('./prompt');
|
|
13
|
+
const { ROOT_AGENTS_FILE, resolveCanonicalSource } = require('./resources');
|
|
14
|
+
const { warn, error, info, fileLine, skippedLine, blank, logo, section } = require('./output');
|
|
15
|
+
|
|
16
|
+
async function update() {
|
|
17
|
+
const cwd = process.cwd();
|
|
18
|
+
const legacyAgentDir = path.join(cwd, '.agent');
|
|
19
|
+
const { version } = require(path.join(__dirname, '..', 'package.json'));
|
|
20
|
+
const installState = await detectInstallState(cwd);
|
|
21
|
+
const legacyAgentExists = await pathExists(legacyAgentDir);
|
|
22
|
+
const isLegacyMigration = installState.selectedTargets.length === 0 && legacyAgentExists;
|
|
23
|
+
const detectedTargetIds = isLegacyMigration ? ['antigravity'] : installState.selectedTargets;
|
|
24
|
+
|
|
25
|
+
if (detectedTargetIds.length === 0 && !legacyAgentExists) {
|
|
26
|
+
logo();
|
|
27
|
+
error('No supported Anws target layout found in current directory.');
|
|
28
|
+
info('Run `anws init` first to set up the workflow system.');
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const targetPlans = buildProjectionPlan(detectedTargetIds);
|
|
33
|
+
const detectedTargetPlans = buildProjectionPlan(detectedTargetIds);
|
|
34
|
+
|
|
35
|
+
const srcAgents = ROOT_AGENTS_FILE;
|
|
36
|
+
|
|
37
|
+
if (isLegacyMigration) {
|
|
38
|
+
logo();
|
|
39
|
+
blank();
|
|
40
|
+
printLegacyMigrationNotice();
|
|
41
|
+
blank();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const versionState = await detectUpgrade({ cwd, version });
|
|
45
|
+
const targetContexts = [];
|
|
46
|
+
|
|
47
|
+
for (const targetPlan of targetPlans) {
|
|
48
|
+
const target = getTarget(targetPlan.targetId);
|
|
49
|
+
const agentsDecision = target.id === 'antigravity'
|
|
50
|
+
? await resolveAgentsInstall({
|
|
51
|
+
cwd,
|
|
52
|
+
askMigrate,
|
|
53
|
+
forceYes: !!global.__ANWS_FORCE_YES
|
|
54
|
+
})
|
|
55
|
+
: {
|
|
56
|
+
shouldWriteRootAgents: false,
|
|
57
|
+
shouldWarnMigration: false,
|
|
58
|
+
rootExists: false,
|
|
59
|
+
legacyExists: false
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
if (!agentsDecision.shouldWriteRootAgents && agentsDecision.legacyExists) {
|
|
63
|
+
info('Keeping legacy .agent/rules/agents.md. Will not pull root AGENTS.md.');
|
|
64
|
+
}
|
|
65
|
+
if (agentsDecision.shouldWarnMigration) {
|
|
66
|
+
printLegacyMigrationWarning();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
let agentsUpdatePlan = null;
|
|
70
|
+
if (agentsDecision.shouldWriteRootAgents && agentsDecision.rootExists) {
|
|
71
|
+
const templateContent = await fs.readFile(srcAgents, 'utf8');
|
|
72
|
+
const existingContent = await fs.readFile(path.join(cwd, 'AGENTS.md'), 'utf8');
|
|
73
|
+
agentsUpdatePlan = planAgentsUpdate({ templateContent, existingContent });
|
|
74
|
+
|
|
75
|
+
if (agentsUpdatePlan.warning) {
|
|
76
|
+
warn(agentsUpdatePlan.warning);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const rawChanges = await collectManagedFileDiffs({
|
|
81
|
+
cwd,
|
|
82
|
+
projectionPlan: [targetPlan],
|
|
83
|
+
srcAgents,
|
|
84
|
+
shouldWriteRootAgents: agentsDecision.shouldWriteRootAgents,
|
|
85
|
+
agentsUpdatePlan
|
|
86
|
+
});
|
|
87
|
+
const changes = rawChanges.filter((item) => {
|
|
88
|
+
if (item.file !== 'AGENTS.md') return true;
|
|
89
|
+
if (agentsUpdatePlan && agentsUpdatePlan.mode === 'skip') return false;
|
|
90
|
+
return agentsDecision.shouldWriteRootAgents;
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
targetContexts.push({
|
|
94
|
+
target,
|
|
95
|
+
targetPlan,
|
|
96
|
+
agentsDecision,
|
|
97
|
+
agentsUpdatePlan,
|
|
98
|
+
changes
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const changes = targetContexts.flatMap((context) => context.changes);
|
|
103
|
+
|
|
104
|
+
if (!versionState.needUpgrade) {
|
|
105
|
+
if (!isLegacyMigration) {
|
|
106
|
+
logo();
|
|
107
|
+
blank();
|
|
108
|
+
}
|
|
109
|
+
printTargetSelection(installState, targetContexts.map((context) => context.target));
|
|
110
|
+
if (installState.canRebuildLock && detectedTargetIds.length > 0) {
|
|
111
|
+
const generatedAt = new Date().toISOString();
|
|
112
|
+
await writeInstallLock(cwd, createInstallLock({
|
|
113
|
+
cliVersion: version,
|
|
114
|
+
generatedAt,
|
|
115
|
+
targets: dedupeTargets(detectedTargetPlans.map((targetPlan) => summarizeTargetState(targetPlan, version))),
|
|
116
|
+
lastUpdateSummary: {
|
|
117
|
+
successfulTargets: [],
|
|
118
|
+
failedTargets: [],
|
|
119
|
+
updatedAt: generatedAt
|
|
120
|
+
}
|
|
121
|
+
}));
|
|
122
|
+
info('Rebuilt .anws/install-lock.json from the detected target layout.');
|
|
123
|
+
}
|
|
124
|
+
info(`Already up to date. Latest recorded version is v${versionState.latestVersion || version}.`);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (!isLegacyMigration) {
|
|
129
|
+
logo();
|
|
130
|
+
blank();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
printTargetSelection(installState, targetContexts.map((context) => context.target));
|
|
134
|
+
|
|
135
|
+
const updated = [];
|
|
136
|
+
const skipped = [];
|
|
137
|
+
const successfulTargets = [];
|
|
138
|
+
const failedTargets = [];
|
|
139
|
+
|
|
140
|
+
for (const context of targetContexts) {
|
|
141
|
+
try {
|
|
142
|
+
const result = await writeTargetFiles(cwd, {
|
|
143
|
+
targetPlan: context.targetPlan,
|
|
144
|
+
protectedFiles: context.targetPlan.userProtectedFiles,
|
|
145
|
+
srcAgents,
|
|
146
|
+
shouldWriteRootAgents: context.agentsDecision.shouldWriteRootAgents,
|
|
147
|
+
agentsUpdatePlan: context.agentsUpdatePlan,
|
|
148
|
+
resolveCanonicalSource
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
updated.push(...result.written);
|
|
152
|
+
skipped.push(...result.skipped);
|
|
153
|
+
successfulTargets.push(summarizeTargetState(context.targetPlan, version));
|
|
154
|
+
} catch (error) {
|
|
155
|
+
failedTargets.push({
|
|
156
|
+
targetId: context.target.id,
|
|
157
|
+
targetLabel: context.target.label,
|
|
158
|
+
reason: error.message
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
blank();
|
|
164
|
+
info('Updated files:');
|
|
165
|
+
blank();
|
|
166
|
+
for (const rel of updated) {
|
|
167
|
+
fileLine(rel.replace(/\\/g, '/'));
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (skipped.length > 0) {
|
|
171
|
+
blank();
|
|
172
|
+
info('Skipped (project-specific, preserved):');
|
|
173
|
+
for (const rel of skipped) {
|
|
174
|
+
skippedLine(rel.replace(/\\/g, '/'));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
printTargetUpdateSummary(successfulTargets, failedTargets);
|
|
179
|
+
|
|
180
|
+
const changelogPath = await generateChangelog({
|
|
181
|
+
cwd,
|
|
182
|
+
version,
|
|
183
|
+
changes,
|
|
184
|
+
targetSummary: {
|
|
185
|
+
successfulTargets: successfulTargets.map((item) => `${item.targetLabel} (${item.targetId})`),
|
|
186
|
+
failedTargets: failedTargets.map((item) => `${item.targetLabel} (${item.targetId})`)
|
|
187
|
+
}
|
|
188
|
+
});
|
|
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
|
+
: [];
|
|
196
|
+
const existingLockTargets = installState.canRebuildLock
|
|
197
|
+
? []
|
|
198
|
+
: (installState.lockResult.lock?.targets || []);
|
|
199
|
+
await writeInstallLock(cwd, createInstallLock({
|
|
200
|
+
cliVersion: version,
|
|
201
|
+
generatedAt,
|
|
202
|
+
targets: dedupeTargets([
|
|
203
|
+
...existingLockTargets,
|
|
204
|
+
...retainedDetectedTargets,
|
|
205
|
+
...successfulTargets
|
|
206
|
+
]),
|
|
207
|
+
lastUpdateSummary: {
|
|
208
|
+
successfulTargets: successfulTargets.map((item) => item.targetId),
|
|
209
|
+
failedTargets: failedTargets.map((item) => item.targetId),
|
|
210
|
+
updatedAt: generatedAt
|
|
211
|
+
}
|
|
212
|
+
}));
|
|
213
|
+
|
|
214
|
+
let legacyCleanupLine = '';
|
|
215
|
+
if (isLegacyMigration) {
|
|
216
|
+
legacyCleanupLine = 'Legacy .agent/ was preserved. You can review and delete it manually after migration.';
|
|
217
|
+
const deleted = await maybeDeleteLegacyDir(legacyAgentDir);
|
|
218
|
+
if (deleted) {
|
|
219
|
+
legacyCleanupLine = 'Legacy .agent/ directory was deleted after confirmation.';
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
printUpdateCompletionSummary({
|
|
224
|
+
updatedCount: updated.length,
|
|
225
|
+
skippedCount: skipped.length,
|
|
226
|
+
changelogPath: path.relative(cwd, changelogPath).replace(/\\/g, '/'),
|
|
227
|
+
legacyCleanupLine
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
async function askMigrate() {
|
|
232
|
+
if (global.__ANWS_FORCE_YES) return true;
|
|
233
|
+
|
|
234
|
+
if (!process.stdin.isTTY) {
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return confirm({
|
|
239
|
+
message: 'Legacy .agent/ directory detected. Migrate to .agents/?',
|
|
240
|
+
confirmLabel: 'Migrate',
|
|
241
|
+
cancelLabel: 'Keep legacy',
|
|
242
|
+
defaultValue: false
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async function maybeDeleteLegacyDir(legacyAgentDir) {
|
|
247
|
+
const exists = await pathExists(legacyAgentDir);
|
|
248
|
+
if (!exists) return false;
|
|
249
|
+
|
|
250
|
+
if (global.__ANWS_FORCE_YES) {
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (!process.stdin.isTTY) {
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const shouldDelete = await confirm({
|
|
259
|
+
message: 'Legacy .agent/ directory has been preserved. Delete it now?',
|
|
260
|
+
confirmLabel: 'Delete',
|
|
261
|
+
cancelLabel: 'Keep',
|
|
262
|
+
defaultValue: false
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
if (!shouldDelete) return false;
|
|
266
|
+
|
|
267
|
+
await fs.rm(legacyAgentDir, { recursive: true, force: true });
|
|
268
|
+
return true;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function buildSelectionModeLine() {
|
|
272
|
+
return 'Selection mode: detected target layout';
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function printLegacyMigrationNotice() {
|
|
276
|
+
section('Legacy migration', [
|
|
277
|
+
'Legacy .agent/ directory detected.',
|
|
278
|
+
'anws update will migrate managed files into the Antigravity target structure.',
|
|
279
|
+
'Your old .agent/ directory will be preserved for manual review.'
|
|
280
|
+
], { minWidth: 60 });
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function printTargetSelection(installState, targets) {
|
|
284
|
+
blank();
|
|
285
|
+
section('Target selection', [
|
|
286
|
+
buildSelectionModeLine(),
|
|
287
|
+
`Matched targets: ${targets.map((target) => `${target.label} (${target.id})`).join(', ') || 'none'}`,
|
|
288
|
+
installState.needsFallback ? 'State source: directory scan fallback' : 'State source: install-lock + directory scan',
|
|
289
|
+
...(installState.drift.hasDrift
|
|
290
|
+
? [`State drift detected. Missing on disk: ${installState.drift.missingOnDisk.join(', ') || 'none'}; untracked on disk: ${installState.drift.untrackedOnDisk.join(', ') || 'none'}.`]
|
|
291
|
+
: [])
|
|
292
|
+
]);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function printTargetUpdateSummary(successfulTargets, failedTargets) {
|
|
296
|
+
blank();
|
|
297
|
+
section('Update summary by target', [
|
|
298
|
+
...successfulTargets.map((target) => `✔ ${target.targetLabel} (${target.targetId})`),
|
|
299
|
+
...failedTargets.map((target) => `✖ ${target.targetLabel} (${target.targetId}) — ${target.reason}`)
|
|
300
|
+
]);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function printUpdateCompletionSummary({ updatedCount, skippedCount, changelogPath, legacyCleanupLine }) {
|
|
304
|
+
blank();
|
|
305
|
+
section('Update completed', [
|
|
306
|
+
`✔ Done! ${updatedCount} file(s) updated${skippedCount > 0 ? `, ${skippedCount} skipped` : ''}.`,
|
|
307
|
+
'Managed files have been updated to the latest version.',
|
|
308
|
+
'Your custom files outside the selected target projections were not touched.',
|
|
309
|
+
...(legacyCleanupLine ? [legacyCleanupLine] : []),
|
|
310
|
+
`Generated upgrade record: ${changelogPath}`,
|
|
311
|
+
'Run `/upgrade` in your AI IDE to update your architecture docs.'
|
|
312
|
+
], { minWidth: 60 });
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
module.exports = update;
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@haaaiawd/anws",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.2",
|
|
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",
|
|
@@ -12,15 +12,16 @@
|
|
|
12
12
|
"prompt-engineering",
|
|
13
13
|
"devops-for-ai",
|
|
14
14
|
"skills-framework",
|
|
15
|
+
"craft-authoring",
|
|
15
16
|
"claude-code",
|
|
16
17
|
"github-copilot",
|
|
17
18
|
"cursor",
|
|
18
19
|
"windsurf"
|
|
19
20
|
],
|
|
20
|
-
"homepage": "https://github.com/Haaaiawd/
|
|
21
|
+
"homepage": "https://github.com/Haaaiawd/ANWS",
|
|
21
22
|
"repository": {
|
|
22
23
|
"type": "git",
|
|
23
|
-
"url": "git+https://github.com/Haaaiawd/
|
|
24
|
+
"url": "git+https://github.com/Haaaiawd/ANWS.git"
|
|
24
25
|
},
|
|
25
26
|
"author": "haaaiawd <1134180104@qq.com>",
|
|
26
27
|
"license": "MIT",
|