@haaaiawd/anws 1.2.5 → 2.0.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/README.md +208 -172
- package/bin/cli.js +22 -9
- package/lib/adapters/index.js +157 -0
- package/lib/agents.js +136 -1
- package/lib/changelog.js +187 -0
- package/lib/copy.js +72 -1
- package/lib/diff.js +270 -0
- package/lib/init.js +143 -125
- package/lib/install-state.js +195 -0
- package/lib/manifest.js +184 -42
- package/lib/output.js +185 -13
- package/lib/prompt.js +284 -0
- package/lib/resources/index.js +27 -0
- package/lib/update.js +291 -83
- package/package.json +10 -6
- package/templates/.agents/skills/concept-modeler/SKILL.md +176 -0
- package/templates/{.agent → .agents}/skills/design-reviewer/SKILL.md +6 -6
- package/templates/.agents/skills/nexus-mapper/SKILL.md +306 -0
- package/templates/.agents/skills/nexus-mapper/references/language-customization.md +164 -0
- package/templates/.agents/skills/nexus-mapper/references/output-schema.md +298 -0
- package/templates/.agents/skills/nexus-mapper/references/probe-protocol.md +246 -0
- package/templates/.agents/skills/nexus-mapper/scripts/extract_ast.py +706 -0
- package/templates/.agents/skills/nexus-mapper/scripts/git_detective.py +194 -0
- package/templates/.agents/skills/nexus-mapper/scripts/languages.json +127 -0
- package/templates/.agents/skills/nexus-mapper/scripts/query_graph.py +556 -0
- package/templates/.agents/skills/nexus-mapper/scripts/requirements.txt +6 -0
- package/templates/{.agent → .agents}/skills/report-template/SKILL.md +11 -14
- package/templates/.agents/skills/report-template/references/REPORT_TEMPLATE.md +100 -0
- package/templates/{.agent → .agents}/skills/runtime-inspector/SKILL.md +1 -1
- package/templates/.agents/skills/sequential-thinking/SKILL.md +166 -0
- package/templates/.agents/skills/spec-writer/SKILL.md +108 -0
- package/templates/{.agent → .agents}/skills/spec-writer/references/prd_template.md +1 -1
- package/templates/{.agent → .agents}/skills/system-architect/SKILL.md +3 -3
- package/templates/.agents/skills/system-architect/references/rfc_template.md +59 -0
- package/templates/{.agent → .agents}/skills/system-designer/SKILL.md +6 -6
- package/templates/{.agent → .agents}/skills/system-designer/references/system-design-template.md +75 -25
- package/templates/{.agent → .agents}/skills/task-planner/SKILL.md +1 -1
- package/templates/.agents/skills/task-planner/references/TASK_TEMPLATE.md +144 -0
- package/templates/{.agent → .agents}/skills/task-reviewer/SKILL.md +4 -3
- package/templates/{.agent → .agents}/skills/tech-evaluator/SKILL.md +2 -2
- package/templates/{.agent → .agents}/skills/tech-evaluator/references/ADR_TEMPLATE.md +10 -0
- package/templates/{.agent → .agents}/workflows/blueprint.md +32 -27
- package/templates/{.agent → .agents}/workflows/challenge.md +21 -15
- package/templates/{.agent → .agents}/workflows/change.md +23 -14
- package/templates/{.agent → .agents}/workflows/craft.md +8 -19
- package/templates/{.agent → .agents}/workflows/design-system.md +81 -54
- package/templates/{.agent → .agents}/workflows/explore.md +6 -19
- package/templates/{.agent → .agents}/workflows/forge.md +30 -32
- package/templates/{.agent → .agents}/workflows/genesis.md +68 -56
- package/templates/.agents/workflows/probe.md +168 -0
- package/templates/{.agent → .agents}/workflows/quickstart.md +7 -12
- package/templates/.agents/workflows/upgrade.md +192 -0
- package/templates/AGENTS.md +66 -45
- package/templates/.agent/skills/build-inspector/SKILL.md +0 -83
- package/templates/.agent/skills/complexity-guard/SKILL.md +0 -71
- package/templates/.agent/skills/complexity-guard/references/anti_patterns.md +0 -21
- package/templates/.agent/skills/concept-modeler/SKILL.md +0 -112
- package/templates/.agent/skills/concept-modeler/prompts/GLOSSARY_PROMPT.md +0 -40
- package/templates/.agent/skills/concept-modeler/references/ENTITY_EXTRACTION_PROMPT.md +0 -299
- package/templates/.agent/skills/concept-modeler/scripts/glossary_gen.py +0 -66
- package/templates/.agent/skills/git-forensics/SKILL.md +0 -74
- package/templates/.agent/skills/git-forensics/references/ANALYSIS_METHODOLOGY.md +0 -193
- package/templates/.agent/skills/git-forensics/scripts/__pycache__/git_forensics.cpython-313.pyc +0 -0
- package/templates/.agent/skills/git-forensics/scripts/git_forensics.py +0 -615
- package/templates/.agent/skills/git-forensics/scripts/git_hotspots.py +0 -118
- package/templates/.agent/skills/report-template/references/REPORT_TEMPLATE.md +0 -100
- package/templates/.agent/skills/spec-writer/SKILL.md +0 -108
- package/templates/.agent/skills/system-architect/references/rfc_template.md +0 -59
- package/templates/.agent/skills/task-planner/references/TASK_TEMPLATE.md +0 -144
- package/templates/.agent/workflows/scout.md +0 -139
- /package/templates/{.agent → .agents}/skills/system-designer/references/system-design-detail-template.md +0 -0
package/lib/diff.js
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs/promises');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
const { c } = require('./output');
|
|
6
|
+
|
|
7
|
+
async function pathExists(targetPath) {
|
|
8
|
+
return fs.access(targetPath).then(() => true).catch(() => false);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async function readTextOrEmpty(filePath) {
|
|
12
|
+
const exists = await pathExists(filePath);
|
|
13
|
+
if (!exists) return '';
|
|
14
|
+
return fs.readFile(filePath, 'utf8');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function normalize(text) {
|
|
18
|
+
return text.replace(/\r\n/g, '\n');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function toLines(text) {
|
|
22
|
+
const lines = normalize(text).split('\n');
|
|
23
|
+
while (lines.length > 0 && lines[lines.length - 1] === '') {
|
|
24
|
+
lines.pop();
|
|
25
|
+
}
|
|
26
|
+
return lines;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function createLineDiff(oldContent, newContent, maxPairs = 8) {
|
|
30
|
+
const before = toLines(oldContent);
|
|
31
|
+
const after = toLines(newContent);
|
|
32
|
+
const pairs = [];
|
|
33
|
+
let beforeIndex = 0;
|
|
34
|
+
let afterIndex = 0;
|
|
35
|
+
|
|
36
|
+
while (beforeIndex < before.length || afterIndex < after.length) {
|
|
37
|
+
const oldLine = before[beforeIndex];
|
|
38
|
+
const newLine = after[afterIndex];
|
|
39
|
+
|
|
40
|
+
if (oldLine === newLine) {
|
|
41
|
+
beforeIndex += 1;
|
|
42
|
+
afterIndex += 1;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const nextOldLine = before[beforeIndex + 1];
|
|
47
|
+
const nextNewLine = after[afterIndex + 1];
|
|
48
|
+
|
|
49
|
+
if (nextOldLine === newLine) {
|
|
50
|
+
pairs.push({
|
|
51
|
+
oldLineNumber: oldLine === undefined ? null : beforeIndex + 1,
|
|
52
|
+
newLineNumber: null,
|
|
53
|
+
oldText: oldLine === undefined ? '' : oldLine,
|
|
54
|
+
newText: '',
|
|
55
|
+
kind: 'removed'
|
|
56
|
+
});
|
|
57
|
+
beforeIndex += 1;
|
|
58
|
+
if (pairs.length >= maxPairs) break;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (oldLine === nextNewLine) {
|
|
63
|
+
pairs.push({
|
|
64
|
+
oldLineNumber: null,
|
|
65
|
+
newLineNumber: newLine === undefined ? null : afterIndex + 1,
|
|
66
|
+
oldText: '',
|
|
67
|
+
newText: newLine === undefined ? '' : newLine,
|
|
68
|
+
kind: 'added'
|
|
69
|
+
});
|
|
70
|
+
afterIndex += 1;
|
|
71
|
+
if (pairs.length >= maxPairs) break;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
pairs.push({
|
|
76
|
+
oldLineNumber: oldLine === undefined ? null : beforeIndex + 1,
|
|
77
|
+
newLineNumber: newLine === undefined ? null : afterIndex + 1,
|
|
78
|
+
oldText: oldLine === undefined ? '' : oldLine,
|
|
79
|
+
newText: newLine === undefined ? '' : newLine,
|
|
80
|
+
kind:
|
|
81
|
+
oldLine === undefined
|
|
82
|
+
? 'added'
|
|
83
|
+
: newLine === undefined
|
|
84
|
+
? 'removed'
|
|
85
|
+
: 'modified'
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
beforeIndex += 1;
|
|
89
|
+
afterIndex += 1;
|
|
90
|
+
|
|
91
|
+
if (pairs.length >= maxPairs) break;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return pairs;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function formatLineNumber(value) {
|
|
98
|
+
return value === null ? '-' : String(value);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function toLegacyManagedPath(rel) {
|
|
102
|
+
if (!rel.startsWith('.agents/')) return rel;
|
|
103
|
+
return `.agent/${rel.slice('.agents/'.length)}`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function resolveExistingManagedPath(cwd, rel) {
|
|
107
|
+
const primaryPath = path.join(cwd, rel);
|
|
108
|
+
if (await pathExists(primaryPath)) {
|
|
109
|
+
return { file: rel, absolutePath: primaryPath, sourceKind: 'current' };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const legacyRel = toLegacyManagedPath(rel);
|
|
113
|
+
if (legacyRel !== rel) {
|
|
114
|
+
const legacyPath = path.join(cwd, legacyRel);
|
|
115
|
+
if (await pathExists(legacyPath)) {
|
|
116
|
+
return { file: rel, absolutePath: legacyPath, sourceKind: 'legacy' };
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return { file: rel, absolutePath: primaryPath, sourceKind: 'missing' };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function collectManagedFileDiffs({
|
|
124
|
+
cwd,
|
|
125
|
+
managedFiles,
|
|
126
|
+
projectionPlan = [],
|
|
127
|
+
projectionEntries = [],
|
|
128
|
+
srcAgents,
|
|
129
|
+
shouldWriteRootAgents,
|
|
130
|
+
agentsUpdatePlan = null
|
|
131
|
+
}) {
|
|
132
|
+
const results = [];
|
|
133
|
+
const normalizedProjectionEntries = projectionEntries.length > 0
|
|
134
|
+
? projectionEntries
|
|
135
|
+
: projectionPlan.flatMap((item) => item.projectionEntries || []);
|
|
136
|
+
const normalizedManagedFiles = managedFiles && managedFiles.length > 0
|
|
137
|
+
? managedFiles
|
|
138
|
+
: projectionPlan.flatMap((item) => item.managedFiles || []);
|
|
139
|
+
const projectionMap = new Map(normalizedProjectionEntries.map((item) => [item.outputPath, item]));
|
|
140
|
+
|
|
141
|
+
for (const rel of normalizedManagedFiles) {
|
|
142
|
+
if (rel === 'AGENTS.md' && !shouldWriteRootAgents) {
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const entry = projectionMap.get(rel);
|
|
147
|
+
const srcPath = rel === 'AGENTS.md'
|
|
148
|
+
? srcAgents
|
|
149
|
+
: path.join(path.join(__dirname, '..', 'templates'), entry.source);
|
|
150
|
+
const existing = rel === 'AGENTS.md'
|
|
151
|
+
? { file: rel, absolutePath: path.join(cwd, rel), sourceKind: 'current' }
|
|
152
|
+
: await resolveExistingManagedPath(cwd, rel);
|
|
153
|
+
const destPath = existing.absolutePath;
|
|
154
|
+
|
|
155
|
+
const srcExists = await pathExists(srcPath);
|
|
156
|
+
const destExists = await pathExists(destPath);
|
|
157
|
+
|
|
158
|
+
if (!srcExists && !destExists) continue;
|
|
159
|
+
|
|
160
|
+
if (srcExists && !destExists) {
|
|
161
|
+
results.push({
|
|
162
|
+
file: rel,
|
|
163
|
+
type: 'added',
|
|
164
|
+
summary: [],
|
|
165
|
+
oldContent: '',
|
|
166
|
+
newContent: await readTextOrEmpty(srcPath)
|
|
167
|
+
});
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (!srcExists && destExists) {
|
|
172
|
+
results.push({
|
|
173
|
+
file: rel,
|
|
174
|
+
type: 'deleted',
|
|
175
|
+
summary: [],
|
|
176
|
+
oldContent: await readTextOrEmpty(destPath),
|
|
177
|
+
newContent: ''
|
|
178
|
+
});
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const oldContent = await readTextOrEmpty(destPath);
|
|
183
|
+
let newContent = await readTextOrEmpty(srcPath);
|
|
184
|
+
|
|
185
|
+
if (rel === 'AGENTS.md' && shouldWriteRootAgents && destExists) {
|
|
186
|
+
if (agentsUpdatePlan && agentsUpdatePlan.mode === 'skip') {
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
newContent = agentsUpdatePlan ? agentsUpdatePlan.content : newContent;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (normalize(oldContent) === normalize(newContent)) continue;
|
|
193
|
+
|
|
194
|
+
results.push({
|
|
195
|
+
file: rel,
|
|
196
|
+
type: 'modified',
|
|
197
|
+
summary: createLineDiff(oldContent, newContent),
|
|
198
|
+
oldContent,
|
|
199
|
+
newContent
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return results;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function groupChanges(changes) {
|
|
207
|
+
return {
|
|
208
|
+
added: changes.filter((item) => item.type === 'added'),
|
|
209
|
+
modified: changes.filter((item) => item.type === 'modified'),
|
|
210
|
+
deleted: changes.filter((item) => item.type === 'deleted')
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function printColorBlock(title, color, items, prefix) {
|
|
215
|
+
if (items.length === 0) return;
|
|
216
|
+
console.log(` ${color}${title} (${items.length})${c.reset}`);
|
|
217
|
+
for (const item of items) {
|
|
218
|
+
console.log(` ${prefix} ${item.file}`);
|
|
219
|
+
}
|
|
220
|
+
console.log('');
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function printPreview({ fromVersion, toVersion, changes }) {
|
|
224
|
+
const grouped = groupChanges(changes);
|
|
225
|
+
const fromLabel = fromVersion ? `v${fromVersion}` : 'fresh-install';
|
|
226
|
+
const toLabel = `v${toVersion}`;
|
|
227
|
+
|
|
228
|
+
console.log('╔══════════════════════════════════════════════════════════════╗');
|
|
229
|
+
console.log(`║ ANWS UPDATE PREVIEW - ${fromLabel} → ${toLabel}`.padEnd(63, ' ') + '║');
|
|
230
|
+
console.log('╚══════════════════════════════════════════════════════════════╝');
|
|
231
|
+
console.log('');
|
|
232
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
233
|
+
console.log('📁 文件级变更');
|
|
234
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
235
|
+
console.log('');
|
|
236
|
+
|
|
237
|
+
printColorBlock('新增', c.green, grouped.added, '+');
|
|
238
|
+
printColorBlock('修改', c.yellow, grouped.modified, '~');
|
|
239
|
+
printColorBlock('删除', c.red, grouped.deleted, '-');
|
|
240
|
+
|
|
241
|
+
if (grouped.added.length === 0 && grouped.modified.length === 0 && grouped.deleted.length === 0) {
|
|
242
|
+
console.log(' Already up to date.');
|
|
243
|
+
console.log('');
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
248
|
+
console.log('📄 内容级变更详情');
|
|
249
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
250
|
+
console.log('');
|
|
251
|
+
|
|
252
|
+
for (const item of grouped.modified) {
|
|
253
|
+
console.log(`${c.yellow}${item.file}${c.reset}`);
|
|
254
|
+
console.log('──────────────────────────────────────────────────────────────');
|
|
255
|
+
for (const pair of item.summary) {
|
|
256
|
+
console.log(` old ${formatLineNumber(pair.oldLineNumber).padStart(4, ' ')} | ${c.red}-${c.reset} ${pair.oldText}`);
|
|
257
|
+
console.log(` new ${formatLineNumber(pair.newLineNumber).padStart(4, ' ')} | ${c.green}+${c.reset} ${pair.newText}`);
|
|
258
|
+
console.log(' ----');
|
|
259
|
+
}
|
|
260
|
+
console.log('');
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
console.log('执行 `anws update` 以应用以上变更。');
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
module.exports = {
|
|
267
|
+
collectManagedFileDiffs,
|
|
268
|
+
groupChanges,
|
|
269
|
+
printPreview
|
|
270
|
+
};
|
package/lib/init.js
CHANGED
|
@@ -1,79 +1,119 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const fs = require('node:fs/promises');
|
|
4
3
|
const path = require('node:path');
|
|
5
|
-
const {
|
|
6
|
-
const {
|
|
4
|
+
const { buildProjectionPlan } = require('./manifest');
|
|
5
|
+
const { getTarget, listTargets } = require('./adapters');
|
|
7
6
|
const { resolveAgentsInstall, printLegacyMigrationWarning, pathExists } = require('./agents');
|
|
8
|
-
const {
|
|
7
|
+
const { ensureChangelogDir } = require('./changelog');
|
|
8
|
+
const { ROOT_AGENTS_FILE, resolveCanonicalSource } = require('./resources');
|
|
9
|
+
const { writeTargetFiles } = require('./copy');
|
|
10
|
+
const { createInstallLock, dedupeTargets, detectInstallState, summarizeTargetState, writeInstallLock } = require('./install-state');
|
|
11
|
+
const { selectMultiple, confirm } = require('./prompt');
|
|
12
|
+
const { success, warn, info, fileLine, skippedLine, blank, logo, section } = require('./output');
|
|
9
13
|
|
|
10
|
-
/**
|
|
11
|
-
* anws init — 将工作流系统写入当前项目
|
|
12
|
-
*/
|
|
13
14
|
async function init() {
|
|
14
15
|
const cwd = process.cwd();
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
logo();
|
|
17
|
+
const targets = await selectTargets();
|
|
18
|
+
const targetIds = Array.from(new Set(targets.map((item) => item.id)));
|
|
19
|
+
const targetPlans = buildProjectionPlan(targetIds);
|
|
20
|
+
const installState = await detectInstallState(cwd);
|
|
21
|
+
const srcAgents = ROOT_AGENTS_FILE;
|
|
22
|
+
const cliVersion = require(path.join(__dirname, '..', 'package.json')).version;
|
|
23
|
+
|
|
24
|
+
info('Initializing Anws...');
|
|
25
|
+
info(`Target IDEs: ${targets.map((item) => item.label).join(', ')}`);
|
|
26
|
+
if (installState.needsFallback) {
|
|
27
|
+
info('Install lock missing or unreadable. Falling back to scanned target state.');
|
|
28
|
+
}
|
|
29
|
+
if (installState.drift.hasDrift) {
|
|
30
|
+
warn(`Detected install-state drift. Missing on disk: ${installState.drift.missingOnDisk.join(', ') || 'none'}; untracked on disk: ${installState.drift.untrackedOnDisk.join(', ') || 'none'}.`);
|
|
31
|
+
}
|
|
32
|
+
blank();
|
|
24
33
|
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
const written = [];
|
|
35
|
+
const skipped = [];
|
|
36
|
+
const successfulTargets = [];
|
|
37
|
+
const failedTargets = [];
|
|
38
|
+
|
|
39
|
+
for (const targetPlan of targetPlans) {
|
|
40
|
+
const target = getTarget(targetPlan.targetId);
|
|
41
|
+
const agentsDecision = target.id === 'antigravity'
|
|
42
|
+
? await resolveAgentsInstall({
|
|
43
|
+
cwd,
|
|
44
|
+
askMigrate,
|
|
45
|
+
forceYes: !!global.__ANWS_FORCE_YES
|
|
46
|
+
})
|
|
47
|
+
: {
|
|
48
|
+
shouldWriteRootAgents: false,
|
|
49
|
+
shouldWarnMigration: false
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const conflicting = await findConflicts(cwd, targetPlan.managedFiles);
|
|
53
|
+
if (conflicting.length > 0) {
|
|
54
|
+
const confirmed = await askOverwrite(conflicting.length, target.label);
|
|
55
|
+
if (!confirmed) {
|
|
56
|
+
skipped.push(...targetPlan.managedFiles);
|
|
57
|
+
failedTargets.push({
|
|
58
|
+
targetId: target.id,
|
|
59
|
+
targetLabel: target.label,
|
|
60
|
+
reason: `Skipped ${conflicting.length} conflicting managed file(s)`
|
|
61
|
+
});
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
33
64
|
}
|
|
34
|
-
|
|
35
|
-
const
|
|
65
|
+
|
|
66
|
+
const result = await writeTargetFiles(cwd, {
|
|
67
|
+
targetPlan,
|
|
68
|
+
protectedFiles: targetPlan.userProtectedFiles,
|
|
36
69
|
srcAgents,
|
|
37
|
-
shouldWriteRootAgents: agentsDecision.shouldWriteRootAgents
|
|
70
|
+
shouldWriteRootAgents: agentsDecision.shouldWriteRootAgents,
|
|
71
|
+
resolveCanonicalSource
|
|
38
72
|
});
|
|
73
|
+
|
|
74
|
+
written.push(...result.written);
|
|
75
|
+
skipped.push(...result.skipped);
|
|
76
|
+
successfulTargets.push(summarizeTargetState(targetPlan, cliVersion));
|
|
77
|
+
|
|
39
78
|
if (agentsDecision.shouldWarnMigration) {
|
|
40
79
|
printLegacyMigrationWarning();
|
|
41
80
|
}
|
|
42
|
-
printSummary(updated, skipped, 'updated');
|
|
43
|
-
return;
|
|
44
81
|
}
|
|
45
|
-
// ── 无冲突:直接复制 ─────────────────────────────────────────────────────────
|
|
46
|
-
|
|
47
|
-
logo();
|
|
48
|
-
info('Initializing Antigravity Workflow System...');
|
|
49
|
-
blank();
|
|
50
82
|
|
|
51
|
-
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
83
|
+
await ensureChangelogDir(cwd);
|
|
84
|
+
const existingTargets = installState.lockResult.lock?.targets || [];
|
|
85
|
+
const generatedAt = new Date().toISOString();
|
|
86
|
+
await writeInstallLock(cwd, createInstallLock({
|
|
87
|
+
cliVersion,
|
|
88
|
+
generatedAt,
|
|
89
|
+
targets: dedupeTargets([
|
|
90
|
+
...existingTargets,
|
|
91
|
+
...successfulTargets
|
|
92
|
+
]),
|
|
93
|
+
lastUpdateSummary: {
|
|
94
|
+
successfulTargets: successfulTargets.map((item) => item.targetId),
|
|
95
|
+
failedTargets: failedTargets.map((item) => item.targetId),
|
|
96
|
+
updatedAt: generatedAt
|
|
61
97
|
}
|
|
62
|
-
}
|
|
98
|
+
}));
|
|
63
99
|
|
|
64
|
-
|
|
65
|
-
|
|
100
|
+
printTargetSummary(successfulTargets, failedTargets);
|
|
101
|
+
|
|
102
|
+
for (const rel of written) {
|
|
103
|
+
fileLine(rel.replace(/\\/g, '/'));
|
|
66
104
|
}
|
|
67
105
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
106
|
+
if (skipped.length > 0) {
|
|
107
|
+
blank();
|
|
108
|
+
info('Skipped (project-specific, preserved):');
|
|
109
|
+
for (const rel of skipped) {
|
|
110
|
+
skippedLine(rel.replace(/\\/g, '/'));
|
|
111
|
+
}
|
|
72
112
|
}
|
|
73
113
|
|
|
74
114
|
blank();
|
|
75
|
-
success(`Done! ${written.length} files written
|
|
76
|
-
printNextSteps();
|
|
115
|
+
success(`Done! ${written.length} files written for ${successfulTargets.map((item) => item.targetLabel).join(', ') || 'selected targets'}.`);
|
|
116
|
+
printNextSteps(targets);
|
|
77
117
|
}
|
|
78
118
|
|
|
79
119
|
// ─── 辅助函数 ──────────────────────────────────────────────────────────────────
|
|
@@ -82,9 +122,9 @@ async function init() {
|
|
|
82
122
|
* 找出 cwd 中已存在的托管文件列表。
|
|
83
123
|
* @returns {Promise<string[]>} 已存在的托管文件相对路径数组
|
|
84
124
|
*/
|
|
85
|
-
async function findConflicts(cwd) {
|
|
125
|
+
async function findConflicts(cwd, managedFiles) {
|
|
86
126
|
const conflicts = [];
|
|
87
|
-
for (const rel of
|
|
127
|
+
for (const rel of managedFiles) {
|
|
88
128
|
const abs = path.join(cwd, rel);
|
|
89
129
|
const exists = await pathExists(abs);
|
|
90
130
|
if (exists) conflicts.push(rel);
|
|
@@ -97,26 +137,19 @@ async function findConflicts(cwd) {
|
|
|
97
137
|
* 非 TTY 环境(如 CI)自动返回 false。
|
|
98
138
|
* @returns {Promise<boolean>}
|
|
99
139
|
*/
|
|
100
|
-
async function askOverwrite(count) {
|
|
140
|
+
async function askOverwrite(count, label) {
|
|
101
141
|
if (global.__ANWS_FORCE_YES) return true;
|
|
102
142
|
|
|
103
|
-
// 非 TTY 环境:默认不覆盖,防止 CI 挂起
|
|
104
143
|
if (!process.stdin.isTTY) {
|
|
105
144
|
warn(`${count} managed file(s) already exist. Non-TTY: skipping overwrite.`);
|
|
106
145
|
return false;
|
|
107
146
|
}
|
|
108
147
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
`\n\u26a0 ${count} managed file(s) already exist. Overwrite? [y/N] `,
|
|
115
|
-
(answer) => {
|
|
116
|
-
rl.close();
|
|
117
|
-
resolve(answer.trim().toLowerCase() === 'y');
|
|
118
|
-
}
|
|
119
|
-
);
|
|
148
|
+
return confirm({
|
|
149
|
+
message: `Overwrite ${count} managed file(s) for ${label}?`,
|
|
150
|
+
confirmLabel: 'Overwrite',
|
|
151
|
+
cancelLabel: 'Skip',
|
|
152
|
+
defaultValue: false
|
|
120
153
|
});
|
|
121
154
|
}
|
|
122
155
|
|
|
@@ -127,62 +160,14 @@ async function askMigrate() {
|
|
|
127
160
|
return false;
|
|
128
161
|
}
|
|
129
162
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
'\n\u26a0 Legacy .agent/rules/agents.md detected. Do you want to migrate to root AGENTS.md? [y/N] ',
|
|
136
|
-
(answer) => {
|
|
137
|
-
rl.close();
|
|
138
|
-
resolve(answer.trim().toLowerCase() === 'y');
|
|
139
|
-
}
|
|
140
|
-
);
|
|
163
|
+
return confirm({
|
|
164
|
+
message: 'Legacy .agent/ directory detected. Migrate to .agents/?',
|
|
165
|
+
confirmLabel: 'Migrate',
|
|
166
|
+
cancelLabel: 'Keep legacy',
|
|
167
|
+
defaultValue: false
|
|
141
168
|
});
|
|
142
169
|
}
|
|
143
170
|
|
|
144
|
-
/**
|
|
145
|
-
* 仅覆盖 MANAGED_FILES 清单内的文件,用户自有文件不受影响。
|
|
146
|
-
* USER_PROTECTED_FILES 中的文件即便冲突也跳过,保留用户修改。
|
|
147
|
-
* @returns {{ written: string[], skipped: string[] }}
|
|
148
|
-
*/
|
|
149
|
-
async function overwriteManaged(srcRoot, cwd, options = {}) {
|
|
150
|
-
const srcBase = path.dirname(srcRoot); // templates/
|
|
151
|
-
const written = [];
|
|
152
|
-
const skipped = [];
|
|
153
|
-
const shouldWriteRootAgents = options.shouldWriteRootAgents !== false;
|
|
154
|
-
const srcAgents = options.srcAgents || path.join(srcBase, 'AGENTS.md');
|
|
155
|
-
|
|
156
|
-
for (const rel of MANAGED_FILES) {
|
|
157
|
-
if (rel === 'AGENTS.md' && !shouldWriteRootAgents) {
|
|
158
|
-
skipped.push(rel);
|
|
159
|
-
continue;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// 受保护文件:文件已存在时跳过,交给用户自行维护
|
|
163
|
-
if (USER_PROTECTED_FILES.includes(rel)) {
|
|
164
|
-
const destPath = path.join(cwd, rel);
|
|
165
|
-
const exists = await pathExists(destPath);
|
|
166
|
-
if (exists) {
|
|
167
|
-
skipped.push(rel);
|
|
168
|
-
continue;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const srcPath = rel === 'AGENTS.md' ? srcAgents : path.join(srcBase, rel);
|
|
173
|
-
const destPath = path.join(cwd, rel);
|
|
174
|
-
|
|
175
|
-
await fs.mkdir(path.dirname(destPath), { recursive: true });
|
|
176
|
-
const srcExists = await pathExists(srcPath);
|
|
177
|
-
if (srcExists) {
|
|
178
|
-
await fs.copyFile(srcPath, destPath);
|
|
179
|
-
written.push(rel);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
return { written, skipped };
|
|
184
|
-
}
|
|
185
|
-
|
|
186
171
|
/**
|
|
187
172
|
* 打印操作摘要(更新场景)。
|
|
188
173
|
* @param {string[]} files 已写入的文件
|
|
@@ -211,11 +196,44 @@ function printSummary(files, skipped = [], action) {
|
|
|
211
196
|
}
|
|
212
197
|
}
|
|
213
198
|
|
|
214
|
-
function
|
|
199
|
+
async function selectTargets() {
|
|
200
|
+
if (global.__ANWS_TARGET_IDS && global.__ANWS_TARGET_IDS.length > 0) {
|
|
201
|
+
return global.__ANWS_TARGET_IDS.map((targetId) => getTarget(targetId));
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (!process.stdin.isTTY) {
|
|
205
|
+
return [getTarget('antigravity')];
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const targets = listTargets();
|
|
209
|
+
|
|
210
|
+
return selectMultiple({
|
|
211
|
+
message: 'Choose your target AI IDEs:',
|
|
212
|
+
options: targets.map((target) => ({ label: target.label, value: target.id })),
|
|
213
|
+
initialSelectedIndexes: [1]
|
|
214
|
+
}).then((selectedOptions) => selectedOptions.map((option) => getTarget(option.value)));
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function printNextSteps(targets) {
|
|
218
|
+
blank();
|
|
219
|
+
section('Next steps', targets.some((target) => target.rootAgentFile)
|
|
220
|
+
? [
|
|
221
|
+
'1. Read AGENTS.md to understand the system',
|
|
222
|
+
'2. Run /quickstart in your AI assistant to analyze and start the workflow'
|
|
223
|
+
]
|
|
224
|
+
: [
|
|
225
|
+
'1. Review files written under the selected target directories',
|
|
226
|
+
'2. Run /quickstart in your AI assistant to analyze and start the workflow'
|
|
227
|
+
]);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function printTargetSummary(successfulTargets, failedTargets) {
|
|
215
231
|
blank();
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
232
|
+
section('Target summary', [
|
|
233
|
+
...successfulTargets.map((target) => `✔ ${target.targetLabel} (${target.targetId})`),
|
|
234
|
+
...failedTargets.map((target) => `✖ ${target.targetLabel} (${target.targetId}) — ${target.reason}`)
|
|
235
|
+
]);
|
|
219
236
|
}
|
|
220
237
|
|
|
221
238
|
module.exports = init;
|
|
239
|
+
|