@haaaiawd/anws 2.0.3 → 2.0.4

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
@@ -15,10 +15,11 @@ const { success, warn, info, fileLine, skippedLine, blank, logo, section } = req
15
15
  async function init() {
16
16
  const cwd = process.cwd();
17
17
  logo();
18
- const targets = await selectTargets();
18
+ const installState = await detectInstallState(cwd);
19
+ const retainedTargetIds = await resolveRetainedTargetIds(cwd, installState);
20
+ const targets = await selectTargets(installState, retainedTargetIds);
19
21
  const targetIds = Array.from(new Set(targets.map((item) => item.id)));
20
22
  const targetPlans = buildProjectionPlan(targetIds);
21
- const installState = await detectInstallState(cwd);
22
23
  const srcAgents = ROOT_AGENTS_FILE;
23
24
  const cliVersion = require(path.join(__dirname, '..', 'package.json')).version;
24
25
 
@@ -40,6 +41,7 @@ async function init() {
40
41
 
41
42
  for (const targetPlan of targetPlans) {
42
43
  const target = getTarget(targetPlan.targetId);
44
+ const targetAlreadyInstalled = retainedTargetIds.includes(target.id);
43
45
  const rootAgentsExists = await pathExists(path.join(cwd, 'AGENTS.md'));
44
46
  const agentsDecision = target.id === 'antigravity'
45
47
  ? await resolveAgentsInstall({
@@ -60,7 +62,11 @@ async function init() {
60
62
  agentsUpdatePlan = planAgentsUpdate({ templateContent, existingContent });
61
63
  }
62
64
 
63
- const conflicting = await findConflicts(cwd, targetPlan.managedFiles, sessionWrittenFiles);
65
+ const conflicting = await findConflicts(
66
+ cwd,
67
+ targetAlreadyInstalled ? [] : targetPlan.managedFiles.filter((rel) => rel !== 'AGENTS.md'),
68
+ sessionWrittenFiles
69
+ );
64
70
  if (conflicting.length > 0) {
65
71
  const confirmed = await askOverwrite(conflicting.length, target.label);
66
72
  if (!confirmed) {
@@ -214,24 +220,79 @@ function printSummary(files, skipped = [], action) {
214
220
  }
215
221
  }
216
222
 
217
- async function selectTargets() {
223
+ async function selectTargets(installState, retainedTargetIds = []) {
224
+ const installedTargetIds = new Set(retainedTargetIds);
225
+
218
226
  if (global.__ANWS_TARGET_IDS && global.__ANWS_TARGET_IDS.length > 0) {
219
- return global.__ANWS_TARGET_IDS.map((targetId) => getTarget(targetId));
227
+ return Array.from(new Set([
228
+ ...retainedTargetIds,
229
+ ...global.__ANWS_TARGET_IDS
230
+ ])).map((targetId) => getTarget(targetId));
220
231
  }
221
232
 
222
233
  if (!process.stdin.isTTY) {
223
- return [getTarget('antigravity')];
234
+ return retainedTargetIds.length > 0
235
+ ? retainedTargetIds.map((targetId) => getTarget(targetId))
236
+ : [getTarget('antigravity')];
224
237
  }
225
238
 
226
239
  const targets = listTargets();
240
+ const lockedIndexes = [];
241
+ const initialSelectedIndexes = [];
242
+
243
+ for (const [index, target] of targets.entries()) {
244
+ if (installedTargetIds.has(target.id)) {
245
+ lockedIndexes.push(index);
246
+ initialSelectedIndexes.push(index);
247
+ }
248
+ }
249
+
250
+ if (initialSelectedIndexes.length === 0) {
251
+ const antigravityIndex = targets.findIndex((target) => target.id === 'antigravity');
252
+ if (antigravityIndex >= 0) {
253
+ initialSelectedIndexes.push(antigravityIndex);
254
+ }
255
+ }
227
256
 
228
257
  return selectMultiple({
229
258
  message: 'Choose your target AI IDEs:',
230
- options: targets.map((target) => ({ label: target.label, value: target.id })),
231
- initialSelectedIndexes: [1]
259
+ options: targets.map((target) => ({
260
+ label: target.label,
261
+ value: target.id,
262
+ locked: installedTargetIds.has(target.id)
263
+ })),
264
+ initialSelectedIndexes,
265
+ lockedIndexes
232
266
  }).then((selectedOptions) => selectedOptions.map((option) => getTarget(option.value)));
233
267
  }
234
268
 
269
+ async function resolveRetainedTargetIds(cwd, installState) {
270
+ if (!installState.needsFallback && !installState.drift.hasDrift) {
271
+ return installState.selectedTargets;
272
+ }
273
+
274
+ const retainedTargetIds = [];
275
+
276
+ for (const targetId of installState.selectedTargets) {
277
+ const [targetPlan] = buildProjectionPlan([targetId]);
278
+ const managedFiles = (targetPlan?.managedFiles || []).filter((rel) => rel !== 'AGENTS.md');
279
+ if (managedFiles.length === 0) {
280
+ retainedTargetIds.push(targetId);
281
+ continue;
282
+ }
283
+
284
+ const managedExists = await Promise.all(
285
+ managedFiles.map((rel) => pathExists(path.join(cwd, rel)))
286
+ );
287
+
288
+ if (managedExists.every(Boolean)) {
289
+ retainedTargetIds.push(targetId);
290
+ }
291
+ }
292
+
293
+ return retainedTargetIds;
294
+ }
295
+
235
296
  function printNextSteps(targets) {
236
297
  blank();
237
298
  section('Next steps', targets.some((target) => target.rootAgentFile)
package/lib/prompt.js CHANGED
@@ -14,12 +14,18 @@ const KEY = {
14
14
  ARROW_LEFT: '\u001b[D'
15
15
  };
16
16
 
17
- async function selectMultiple({ message, options, initialSelectedIndexes = [] }) {
17
+ async function selectMultiple({ message, options, initialSelectedIndexes = [], lockedIndexes = [] }) {
18
+ const normalizedLockedIndexes = new Set(lockedIndexes.filter((index) => index >= 0 && index < options.length));
19
+ const normalizedInitialSelectedIndexes = Array.from(new Set([
20
+ ...initialSelectedIndexes.filter((index) => index >= 0 && index < options.length),
21
+ ...normalizedLockedIndexes
22
+ ]));
23
+
18
24
  if (!process.stdin.isTTY || !process.stdout.isTTY) {
19
- return initialSelectedIndexes.map((index) => options[index]).filter(Boolean);
25
+ return normalizedInitialSelectedIndexes.map((index) => options[index]).filter(Boolean);
20
26
  }
21
27
 
22
- const selected = new Set(initialSelectedIndexes.filter((index) => index >= 0 && index < options.length));
28
+ const selected = new Set(normalizedInitialSelectedIndexes);
23
29
  const state = {
24
30
  cursorIndex: 0,
25
31
  errorMessage: ''
@@ -49,6 +55,10 @@ async function selectMultiple({ message, options, initialSelectedIndexes = [] })
49
55
  }
50
56
 
51
57
  if (key === KEY.SPACE) {
58
+ if (normalizedLockedIndexes.has(state.cursorIndex)) {
59
+ state.errorMessage = 'Already installed targets are locked. You can only add more targets.';
60
+ return 'render';
61
+ }
52
62
  if (selected.has(state.cursorIndex)) {
53
63
  selected.delete(state.cursorIndex);
54
64
  } else {
@@ -121,7 +131,8 @@ function renderMultiSelect({ message, options, selected, cursorIndex, errorMessa
121
131
  const isSelected = selected.has(index);
122
132
  const cursor = isActive ? colorize('❯', PALETTE.brand) : ' ';
123
133
  const mark = isSelected ? colorize('◉', PALETTE.brand) : colorize('◌', PALETTE.muted);
124
- const label = isActive ? colorize(option.label, PALETTE.ink) : option.label;
134
+ const labelText = option.locked ? `${option.label} ${colorize('(installed)', PALETTE.muted)}` : option.label;
135
+ const label = isActive ? colorize(labelText, PALETTE.ink) : labelText;
125
136
  return `${cursor} ${mark} ${label}`;
126
137
  });
127
138
 
@@ -133,7 +144,7 @@ function renderMultiSelect({ message, options, selected, cursorIndex, errorMessa
133
144
  '',
134
145
  ...optionLines,
135
146
  '',
136
- errorMessage ? colorize(errorMessage, c.yellow) : colorize('Choose any set of targets, then press Enter.', PALETTE.muted)
147
+ errorMessage ? colorize(errorMessage, c.yellow) : colorize('Choose targets to add. Installed targets stay selected.', PALETTE.muted)
137
148
  ],
138
149
  accent: PALETTE.brand,
139
150
  borderTone: PALETTE.muted,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haaaiawd/anws",
3
- "version": "2.0.3",
3
+ "version": "2.0.4",
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",