@event4u/agent-config 9.10.0 → 9.11.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.
Files changed (121) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +59 -0
  3. package/README.md +12 -15
  4. package/agents/templates/.ai-council.yml.example +481 -0
  5. package/agents/templates/.ai-video.xml.example +247 -0
  6. package/dist/agent-src/rules/design-fidelity.md +1 -1
  7. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +15 -2
  8. package/dist/agent-src/skills/fe-design/SKILL.md +10 -0
  9. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  10. package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +30 -30
  11. package/dist/agent-src/templates/scripts/work_engine/directives/ui/design.ts +88 -33
  12. package/dist/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +20 -0
  13. package/dist/agent-src/templates/scripts/work_engine/directives/ui/review.ts +20 -1
  14. package/dist/agent-src/templates/scripts/work_engine/directives/ui/stack_bundles.ts +179 -0
  15. package/dist/agent-src/templates/scripts/work_engine/stack/detect.ts +155 -4
  16. package/dist/agent-src/templates/scripts/work_engine/state.ts +21 -4
  17. package/dist/cli/initRouting.js +74 -11
  18. package/dist/cli/initRouting.js.map +1 -1
  19. package/dist/cli/main.js +14 -3
  20. package/dist/cli/main.js.map +1 -1
  21. package/dist/cli-delegate/chunk-4SV3XGFA.js +6910 -0
  22. package/dist/cli-delegate/chunk-736JCWLM.js +1104 -0
  23. package/dist/cli-delegate/chunk-7DSAMZFU.js +356 -0
  24. package/dist/cli-delegate/chunk-7HQ52DHU.js +74 -0
  25. package/dist/cli-delegate/chunk-BJGXZNPM.js +266 -0
  26. package/dist/cli-delegate/chunk-FTAISGDQ.js +117 -0
  27. package/dist/cli-delegate/chunk-GME3Q44L.js +82 -0
  28. package/dist/cli-delegate/chunk-GRRPEPRN.js +336 -0
  29. package/dist/cli-delegate/chunk-HJ6DAJHR.js +502 -0
  30. package/dist/cli-delegate/chunk-IR7P7JWA.js +872 -0
  31. package/dist/cli-delegate/chunk-J55WI3RR.js +47 -0
  32. package/dist/cli-delegate/chunk-MCJYCQPF.js +35 -0
  33. package/dist/cli-delegate/chunk-NDJLNC6Q.js +169 -0
  34. package/dist/cli-delegate/chunk-OMIVVCG2.js +26 -0
  35. package/dist/cli-delegate/chunk-OY53J6II.js +7336 -0
  36. package/dist/cli-delegate/chunk-RDGRHAAB.js +259 -0
  37. package/dist/cli-delegate/chunk-TFG57JJM.js +1969 -0
  38. package/dist/cli-delegate/chunk-XX6TOPD7.js +715 -0
  39. package/dist/cli-delegate/chunk-YMFO6FDN.js +10603 -0
  40. package/dist/cli-delegate/cmd_analyze_session.js +294 -0
  41. package/dist/cli-delegate/cmd_conformance.js +646 -0
  42. package/dist/cli-delegate/cmd_converge.js +326 -0
  43. package/dist/cli-delegate/cmd_doctor.js +144 -0
  44. package/dist/cli-delegate/cmd_explain.js +2508 -0
  45. package/dist/cli-delegate/cmd_export.js +296 -0
  46. package/dist/cli-delegate/cmd_fleet.js +332 -0
  47. package/dist/cli-delegate/cmd_memory_get.js +3878 -0
  48. package/dist/cli-delegate/cmd_migrate.js +11 -0
  49. package/dist/cli-delegate/cmd_preflight.js +270 -0
  50. package/dist/cli-delegate/cmd_prune.js +444 -0
  51. package/dist/cli-delegate/cmd_refresh.js +28 -0
  52. package/dist/cli-delegate/cmd_settings_check.js +574 -0
  53. package/dist/cli-delegate/cmd_settings_migrate.js +223 -0
  54. package/dist/cli-delegate/cmd_sync.js +264 -0
  55. package/dist/cli-delegate/cmd_uninstall.js +656 -0
  56. package/dist/cli-delegate/cmd_update.js +425 -0
  57. package/dist/cli-delegate/cmd_upgrade.js +444 -0
  58. package/dist/cli-delegate/cmd_validate.js +305 -0
  59. package/dist/cli-delegate/cmd_versions.js +370 -0
  60. package/dist/discovery/deprecation-report.md +1 -1
  61. package/dist/discovery/discovery-manifest.json +14 -7
  62. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  63. package/dist/discovery/discovery-manifest.summary.md +2 -2
  64. package/dist/discovery/orphan-report.md +1 -1
  65. package/dist/discovery/packs.json +12 -7
  66. package/dist/discovery/trust-report.md +1 -1
  67. package/dist/discovery/workspaces.json +4 -3
  68. package/dist/install/emit_host_rules_cli.js +2 -1
  69. package/dist/install/emit_host_rules_cli.js.map +1 -1
  70. package/dist/install/install.mjs +410 -378
  71. package/dist/install/rule_scope.js +5 -1
  72. package/dist/install/rule_scope.js.map +1 -1
  73. package/dist/install/toolDetection.js +40 -12
  74. package/dist/install/toolDetection.js.map +1 -1
  75. package/dist/install/wizard-plan.js +2 -2
  76. package/dist/install/wizard-plan.js.map +1 -1
  77. package/dist/mcp/registry-manifest.json +1 -1
  78. package/dist/mcp/server.json +2 -2
  79. package/dist/mcp/server.mjs +1614 -765
  80. package/dist/router.json +1 -1
  81. package/package.json +4 -2
  82. package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +30 -30
  83. package/src/agent-src/templates/scripts/work_engine/directives/ui/design.ts +88 -33
  84. package/src/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +20 -0
  85. package/src/agent-src/templates/scripts/work_engine/directives/ui/review.ts +20 -1
  86. package/src/agent-src/templates/scripts/work_engine/directives/ui/stack_bundles.ts +179 -0
  87. package/src/agent-src/templates/scripts/work_engine/stack/detect.ts +155 -4
  88. package/src/agent-src/templates/scripts/work_engine/state.ts +21 -4
  89. package/src/config/discovery/packs.yml +7 -0
  90. package/src/config/evaluator-budgets.json +1 -1
  91. package/src/config/pack-size-budget.json +27 -0
  92. package/src/install/emit_host_rules_cli.ts +2 -1
  93. package/src/install/rule_scope.ts +5 -1
  94. package/src/install/toolDetection.ts +39 -8
  95. package/src/install/wizard-plan.ts +2 -2
  96. package/src/scripts/_cli/cmd_conformance.ts +2 -1
  97. package/src/scripts/_cli/cmd_converge.ts +2 -1
  98. package/src/scripts/_cli/cmd_doctor.ts +214 -13
  99. package/src/scripts/_cli/cmd_export.ts +2 -1
  100. package/src/scripts/_cli/cmd_fleet.ts +2 -1
  101. package/src/scripts/_cli/cmd_migrate.ts +2 -1
  102. package/src/scripts/_cli/cmd_preflight.ts +2 -1
  103. package/src/scripts/_cli/cmd_refresh.ts +2 -1
  104. package/src/scripts/_cli/cmd_update.ts +2 -1
  105. package/src/scripts/_cli/cmd_upgrade.ts +2 -1
  106. package/src/scripts/_cli/cmd_versions.ts +2 -1
  107. package/src/scripts/_cli/detection_report.ts +480 -0
  108. package/src/scripts/_dispatch.bash +52 -14
  109. package/src/scripts/_lib/changelog_eras.ts +103 -9
  110. package/src/scripts/_lib/environment_detector.ts +441 -0
  111. package/src/scripts/_lib/package_root.ts +72 -0
  112. package/src/scripts/ai_council/config.ts +15 -7
  113. package/src/scripts/ai_council/modes.ts +68 -2
  114. package/src/scripts/ai_council/transport_resolver.ts +331 -0
  115. package/src/scripts/check_bundle_path_leakage.ts +10 -4
  116. package/src/scripts/check_dependency_floors.ts +153 -0
  117. package/src/scripts/check_pack_size.ts +188 -0
  118. package/src/scripts/council_cli.ts +6 -2
  119. package/src/scripts/evaluator_umbrella.sh +34 -1
  120. package/src/scripts/lint_eval_fixture_citations.ts +113 -0
  121. package/src/scripts/lint_ui_stack_bundles.ts +170 -0
@@ -0,0 +1,715 @@
1
+ import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);
2
+ import {
3
+ resolve_project_root
4
+ } from "./chunk-HJ6DAJHR.js";
5
+ import {
6
+ resolvePackageRoot
7
+ } from "./chunk-MCJYCQPF.js";
8
+
9
+ // src/scripts/_cli/cmd_migrate.ts
10
+ import { spawnSync } from "node:child_process";
11
+ import * as fs from "node:fs";
12
+ import * as path from "node:path";
13
+ import process from "node:process";
14
+ import { fileURLToPath, pathToFileURL } from "node:url";
15
+ var PACKAGE_NAME_NPM = "@event4u/agent-config";
16
+ var PACKAGE_NAME_COMPOSER = "event4u/agent-config";
17
+ var LEGACY_DIRS = ["vendor", "node_modules"];
18
+ var MANAGED_SYMLINKS = [
19
+ ".augment",
20
+ ".claude",
21
+ ".cursor",
22
+ ".clinerules",
23
+ ".windsurfrules"
24
+ ];
25
+ var GITIGNORE_BLOCK_START = "# >>> event4u/agent-config (managed) >>>";
26
+ var GITIGNORE_BLOCK_END = "# <<< event4u/agent-config (managed) <<<";
27
+ var GITIGNORE_NEW_BODY = ".agent-settings.yml\nagents/sessions/\nagents/runtime/council/responses/\nagents/runtime/council/sessions/\n";
28
+ var LEGACY_SETTINGS_FILES = [".agent-settings.yml", ".agent-user.yml"];
29
+ var LEGACY_STATE_FILENAME = ".implement-ticket-state.json";
30
+ var LEGACY_STATE_V1_FILENAME = ".work-state.json";
31
+ var LEGACY_AGENT_CONFIG_SHELL = "agent-config";
32
+ var _HERE_DIR = path.dirname(fileURLToPath(import.meta.url));
33
+ var ArgparseExit = class extends Error {
34
+ code;
35
+ constructor(code) {
36
+ super(`ArgparseExit(${code})`);
37
+ this.name = "ArgparseExit";
38
+ this.code = code;
39
+ }
40
+ };
41
+ function _stdoutSink() {
42
+ return { write: (t) => process.stdout.write(t) };
43
+ }
44
+ function _stderrSink() {
45
+ return { write: (t) => process.stderr.write(t) };
46
+ }
47
+ function _print(out, line = "") {
48
+ out.write(line + "\n");
49
+ }
50
+ function _jsonStrAscii(s) {
51
+ let out = '"';
52
+ for (let i = 0; i < s.length; i++) {
53
+ const code = s.charCodeAt(i);
54
+ const ch = s[i];
55
+ switch (ch) {
56
+ case '"':
57
+ out += '\\"';
58
+ break;
59
+ case "\\":
60
+ out += "\\\\";
61
+ break;
62
+ case "\n":
63
+ out += "\\n";
64
+ break;
65
+ case "\r":
66
+ out += "\\r";
67
+ break;
68
+ case " ":
69
+ out += "\\t";
70
+ break;
71
+ case "\b":
72
+ out += "\\b";
73
+ break;
74
+ case "\f":
75
+ out += "\\f";
76
+ break;
77
+ default:
78
+ if (code < 32 || code > 126) {
79
+ out += "\\u" + code.toString(16).padStart(4, "0");
80
+ } else {
81
+ out += ch;
82
+ }
83
+ }
84
+ }
85
+ return out + '"';
86
+ }
87
+ function _jsonScalarAscii(value) {
88
+ if (value === null || value === void 0) return "null";
89
+ if (typeof value === "boolean") return value ? "true" : "false";
90
+ if (typeof value === "number") {
91
+ if (!Number.isFinite(value)) {
92
+ if (Number.isNaN(value)) return "NaN";
93
+ return value > 0 ? "Infinity" : "-Infinity";
94
+ }
95
+ if (Number.isInteger(value)) return String(value);
96
+ return String(value);
97
+ }
98
+ if (typeof value === "string") return _jsonStrAscii(value);
99
+ return null;
100
+ }
101
+ function _dumpIndentAscii(value, indent, depth) {
102
+ const scalar = _jsonScalarAscii(value);
103
+ if (scalar !== null) return scalar;
104
+ const pad = " ".repeat(indent * (depth + 1));
105
+ const closePad = " ".repeat(indent * depth);
106
+ if (Array.isArray(value)) {
107
+ if (value.length === 0) return "[]";
108
+ const items = value.map((v) => pad + _dumpIndentAscii(v, indent, depth + 1));
109
+ return `[
110
+ ${items.join(",\n")}
111
+ ${closePad}]`;
112
+ }
113
+ if (typeof value === "object" && value !== null) {
114
+ const obj = value;
115
+ const keys = Object.keys(obj);
116
+ if (keys.length === 0) return "{}";
117
+ const items = keys.map(
118
+ (k) => `${pad}${_jsonStrAscii(k)}: ${_dumpIndentAscii(obj[k], indent, depth + 1)}`
119
+ );
120
+ return `{
121
+ ${items.join(",\n")}
122
+ ${closePad}}`;
123
+ }
124
+ return _jsonStrAscii(String(value));
125
+ }
126
+ function _jsonDumpsIndentAscii(value, indent) {
127
+ return _dumpIndentAscii(value, indent, 0);
128
+ }
129
+ function _isFile(p) {
130
+ try {
131
+ return fs.statSync(p).isFile();
132
+ } catch {
133
+ return false;
134
+ }
135
+ }
136
+ function _isDir(p) {
137
+ try {
138
+ return fs.statSync(p).isDirectory();
139
+ } catch {
140
+ return false;
141
+ }
142
+ }
143
+ function _isSymlink(p) {
144
+ try {
145
+ return fs.lstatSync(p).isSymbolicLink();
146
+ } catch {
147
+ return false;
148
+ }
149
+ }
150
+ function _exists(p) {
151
+ try {
152
+ fs.lstatSync(p);
153
+ return true;
154
+ } catch {
155
+ return false;
156
+ }
157
+ }
158
+ function _readText(p) {
159
+ return fs.readFileSync(p, { encoding: "utf-8" });
160
+ }
161
+ function _writeText(p, text) {
162
+ fs.writeFileSync(p, text, { encoding: "utf-8" });
163
+ }
164
+ function _jsonLoadFile(p) {
165
+ return JSON.parse(_readText(p));
166
+ }
167
+ function _isPlainObject(value) {
168
+ return typeof value === "object" && value !== null && !Array.isArray(value);
169
+ }
170
+ function _detect_npm(pkg_json) {
171
+ if (!_isFile(pkg_json)) {
172
+ return false;
173
+ }
174
+ let data;
175
+ try {
176
+ data = _jsonLoadFile(pkg_json);
177
+ } catch {
178
+ return false;
179
+ }
180
+ if (!_isPlainObject(data)) {
181
+ return false;
182
+ }
183
+ for (const key of ["dependencies", "devDependencies"]) {
184
+ const section = data[key] ?? {};
185
+ if (_isPlainObject(section) && PACKAGE_NAME_NPM in section) {
186
+ return true;
187
+ }
188
+ }
189
+ return false;
190
+ }
191
+ function _detect_composer(composer_json) {
192
+ if (!_isFile(composer_json)) {
193
+ return false;
194
+ }
195
+ let data;
196
+ try {
197
+ data = _jsonLoadFile(composer_json);
198
+ } catch {
199
+ return false;
200
+ }
201
+ if (!_isPlainObject(data)) {
202
+ return false;
203
+ }
204
+ for (const key of ["require", "require-dev"]) {
205
+ const section = data[key] ?? {};
206
+ if (_isPlainObject(section) && PACKAGE_NAME_COMPOSER in section) {
207
+ return true;
208
+ }
209
+ }
210
+ return false;
211
+ }
212
+ function _classify_symlink(link) {
213
+ if (!_isSymlink(link)) {
214
+ return null;
215
+ }
216
+ let target;
217
+ try {
218
+ target = fs.readlinkSync(link);
219
+ } catch {
220
+ return null;
221
+ }
222
+ const target_str = target;
223
+ if (LEGACY_DIRS.some((seg) => target_str.split("/").includes(seg))) {
224
+ return "legacy";
225
+ }
226
+ return "user";
227
+ }
228
+ function _detect_legacy_state(project) {
229
+ return _isFile(path.join(project, LEGACY_STATE_FILENAME));
230
+ }
231
+ function _detect_legacy_settings(project) {
232
+ const found = [];
233
+ for (const name of LEGACY_SETTINGS_FILES) {
234
+ const flat = path.join(project, name);
235
+ if (_isFile(flat)) {
236
+ found.push(flat);
237
+ }
238
+ const typed = path.join(project, "settings", name);
239
+ if (_isFile(typed)) {
240
+ found.push(typed);
241
+ }
242
+ }
243
+ return found;
244
+ }
245
+ function _detect_empty_shell(project) {
246
+ const shell = path.join(project, LEGACY_AGENT_CONFIG_SHELL);
247
+ if (!_isDir(shell) || _isSymlink(shell)) {
248
+ return false;
249
+ }
250
+ try {
251
+ return fs.readdirSync(shell).length === 0;
252
+ } catch {
253
+ return false;
254
+ }
255
+ }
256
+ function _detect_already_migrated(project) {
257
+ if (_detect_npm(path.join(project, "package.json"))) {
258
+ return false;
259
+ }
260
+ if (_detect_composer(path.join(project, "composer.json"))) {
261
+ return false;
262
+ }
263
+ for (const name of MANAGED_SYMLINKS) {
264
+ if (_classify_symlink(path.join(project, name)) === "legacy") {
265
+ return false;
266
+ }
267
+ }
268
+ if (_detect_legacy_state(project)) {
269
+ return false;
270
+ }
271
+ if (_detect_legacy_settings(project).length) {
272
+ return false;
273
+ }
274
+ if (_detect_empty_shell(project)) {
275
+ return false;
276
+ }
277
+ return true;
278
+ }
279
+ function _strip_npm_entry(pkg_json) {
280
+ let data;
281
+ try {
282
+ data = _jsonLoadFile(pkg_json);
283
+ } catch {
284
+ return false;
285
+ }
286
+ if (!_isPlainObject(data)) {
287
+ return false;
288
+ }
289
+ let changed = false;
290
+ for (const key of ["dependencies", "devDependencies"]) {
291
+ const section = data[key];
292
+ if (_isPlainObject(section) && PACKAGE_NAME_NPM in section) {
293
+ delete section[PACKAGE_NAME_NPM];
294
+ changed = true;
295
+ if (Object.keys(section).length === 0) {
296
+ delete data[key];
297
+ }
298
+ }
299
+ }
300
+ if (changed) {
301
+ _writeText(pkg_json, _jsonDumpsIndentAscii(data, 2) + "\n");
302
+ }
303
+ return changed;
304
+ }
305
+ function _strip_composer_entry(composer_json) {
306
+ let data;
307
+ try {
308
+ data = _jsonLoadFile(composer_json);
309
+ } catch {
310
+ return false;
311
+ }
312
+ if (!_isPlainObject(data)) {
313
+ return false;
314
+ }
315
+ let changed = false;
316
+ for (const key of ["require", "require-dev"]) {
317
+ const section = data[key];
318
+ if (_isPlainObject(section) && PACKAGE_NAME_COMPOSER in section) {
319
+ delete section[PACKAGE_NAME_COMPOSER];
320
+ changed = true;
321
+ if (Object.keys(section).length === 0) {
322
+ delete data[key];
323
+ }
324
+ }
325
+ }
326
+ if (changed) {
327
+ _writeText(composer_json, _jsonDumpsIndentAscii(data, 2) + "\n");
328
+ }
329
+ return changed;
330
+ }
331
+ function _purge_legacy_symlinks(project) {
332
+ const removed = [];
333
+ const preserved = [];
334
+ for (const name of MANAGED_SYMLINKS) {
335
+ const link = path.join(project, name);
336
+ const kind = _classify_symlink(link);
337
+ if (kind === "legacy") {
338
+ try {
339
+ fs.unlinkSync(link);
340
+ removed.push(name);
341
+ } catch {
342
+ preserved.push(name);
343
+ }
344
+ } else if (kind === "user") {
345
+ preserved.push(name);
346
+ }
347
+ }
348
+ return [removed, preserved];
349
+ }
350
+ function _migrate_state_file(project) {
351
+ const source = path.join(project, LEGACY_STATE_FILENAME);
352
+ if (!_isFile(source)) {
353
+ return null;
354
+ }
355
+ const target = path.join(project, LEGACY_STATE_V1_FILENAME);
356
+ if (_exists(target)) {
357
+ try {
358
+ fs.unlinkSync(source);
359
+ return `removed stale ${LEGACY_STATE_FILENAME} (v1 already present)`;
360
+ } catch {
361
+ return null;
362
+ }
363
+ }
364
+ const migrator = _load_state_migrator();
365
+ if (migrator === null) {
366
+ return null;
367
+ }
368
+ migrator(source, { destination: target, backup: true });
369
+ return `migrated ${LEGACY_STATE_FILENAME} \u2192 ${LEGACY_STATE_V1_FILENAME}`;
370
+ }
371
+ function _load_state_migrator() {
372
+ const pkg_root = resolvePackageRoot(import.meta.url);
373
+ const rel = path.join(
374
+ "agent-src",
375
+ "templates",
376
+ "scripts",
377
+ "work_engine",
378
+ "migration",
379
+ "v0_to_v1.ts"
380
+ );
381
+ const driver = [path.join(pkg_root, "dist", rel), path.join(pkg_root, "src", rel)].find(
382
+ (p) => fs.existsSync(p)
383
+ ) ?? null;
384
+ if (driver === null) {
385
+ return null;
386
+ }
387
+ const binName = process.platform === "win32" ? "tsx.cmd" : "tsx";
388
+ let tsxBin = null;
389
+ for (let dir = pkg_root; ; ) {
390
+ const cand = path.join(dir, "node_modules", ".bin", binName);
391
+ if (fs.existsSync(cand)) {
392
+ tsxBin = cand;
393
+ break;
394
+ }
395
+ const parent = path.dirname(dir);
396
+ if (parent === dir) break;
397
+ dir = parent;
398
+ }
399
+ const command = tsxBin ?? "npx";
400
+ const prefix = tsxBin !== null ? [] : ["tsx"];
401
+ return (source, opts = {}) => {
402
+ const args = [...prefix, driver, source];
403
+ if (opts.destination !== void 0 && opts.destination !== null) {
404
+ args.push("--destination", opts.destination);
405
+ }
406
+ if (opts.backup === false) {
407
+ args.push("--no-backup");
408
+ }
409
+ const r = spawnSync(command, args, { encoding: "utf8" });
410
+ if (r.status !== 0) {
411
+ throw new Error(
412
+ `v0\u2192v1 state migration failed (exit ${r.status ?? "null"}): ${(r.stderr ?? "").trim()}`
413
+ );
414
+ }
415
+ return (r.stdout ?? "").trim();
416
+ };
417
+ }
418
+ function _delete_legacy_settings(project) {
419
+ const removed = [];
420
+ for (const p of _detect_legacy_settings(project)) {
421
+ try {
422
+ fs.unlinkSync(p);
423
+ removed.push(path.relative(project, p));
424
+ } catch {
425
+ continue;
426
+ }
427
+ }
428
+ const settings_dir = path.join(project, "settings");
429
+ if (_isDir(settings_dir) && !_isSymlink(settings_dir)) {
430
+ try {
431
+ if (fs.readdirSync(settings_dir).length === 0) {
432
+ fs.rmdirSync(settings_dir);
433
+ removed.push("settings/");
434
+ }
435
+ } catch {
436
+ }
437
+ }
438
+ return removed;
439
+ }
440
+ function _remove_empty_shell(project) {
441
+ const shell = path.join(project, LEGACY_AGENT_CONFIG_SHELL);
442
+ if (!_detect_empty_shell(project)) {
443
+ return false;
444
+ }
445
+ try {
446
+ fs.rmdirSync(shell);
447
+ } catch {
448
+ return false;
449
+ }
450
+ return true;
451
+ }
452
+ function _reEscape(s) {
453
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
454
+ }
455
+ function _update_gitignore(project) {
456
+ const gitignore = path.join(project, ".gitignore");
457
+ const block = `${GITIGNORE_BLOCK_START}
458
+ ${GITIGNORE_NEW_BODY}${GITIGNORE_BLOCK_END}
459
+ `;
460
+ if (!_exists(gitignore)) {
461
+ _writeText(gitignore, block);
462
+ return true;
463
+ }
464
+ const text = _readText(gitignore);
465
+ const pattern = new RegExp(
466
+ _reEscape(GITIGNORE_BLOCK_START) + ".*?" + _reEscape(GITIGNORE_BLOCK_END) + "\\n?",
467
+ "s"
468
+ );
469
+ let new_text;
470
+ if (pattern.test(text)) {
471
+ new_text = text.replace(pattern, () => block);
472
+ } else {
473
+ new_text = text;
474
+ if (new_text && !new_text.endsWith("\n")) {
475
+ new_text += "\n";
476
+ }
477
+ new_text += block;
478
+ }
479
+ if (new_text === text) {
480
+ return false;
481
+ }
482
+ _writeText(gitignore, new_text);
483
+ return true;
484
+ }
485
+ function _build_plan(project) {
486
+ return {
487
+ npm: _detect_npm(path.join(project, "package.json")),
488
+ composer: _detect_composer(path.join(project, "composer.json")),
489
+ symlinks_legacy: MANAGED_SYMLINKS.filter(
490
+ (name) => _classify_symlink(path.join(project, name)) === "legacy"
491
+ ),
492
+ symlinks_user: MANAGED_SYMLINKS.filter(
493
+ (name) => _classify_symlink(path.join(project, name)) === "user"
494
+ ),
495
+ state_file: _isFile(path.join(project, LEGACY_STATE_FILENAME)),
496
+ settings_files: _detect_legacy_settings(project).map((p) => path.relative(project, p)),
497
+ empty_shell: _detect_empty_shell(project)
498
+ };
499
+ }
500
+ function _plan_lines(plan) {
501
+ const lines = [];
502
+ if (plan.npm) {
503
+ lines.push(`would remove ${PACKAGE_NAME_NPM} from package.json`);
504
+ }
505
+ if (plan.composer) {
506
+ lines.push(`would remove ${PACKAGE_NAME_COMPOSER} from composer.json`);
507
+ }
508
+ for (const name of plan.symlinks_legacy) {
509
+ lines.push(`would remove legacy symlink ${name}`);
510
+ }
511
+ for (const name of plan.symlinks_user) {
512
+ lines.push(`would preserve user-managed ${name} (review manually)`);
513
+ }
514
+ if (plan.state_file) {
515
+ lines.push(`would migrate ${LEGACY_STATE_FILENAME} \u2192 ${LEGACY_STATE_V1_FILENAME}`);
516
+ }
517
+ for (const rel of plan.settings_files) {
518
+ lines.push(`would delete legacy config ${rel}`);
519
+ }
520
+ if (plan.empty_shell) {
521
+ lines.push(`would remove empty ${LEGACY_AGENT_CONFIG_SHELL}/ shell`);
522
+ }
523
+ lines.push("would refresh .gitignore agent-config block");
524
+ return lines;
525
+ }
526
+ function _format_dry_run(plan, out) {
527
+ _print(out, "\u2139\uFE0F legacy install detected \u2014 re-run without --dry-run to migrate:");
528
+ for (const line of _plan_lines(plan)) {
529
+ _print(out, ` - ${line}`);
530
+ }
531
+ }
532
+ function _pending_actions(plan) {
533
+ return Number(plan.npm) + Number(plan.composer) + plan.symlinks_legacy.length + plan.symlinks_user.length + Number(plan.state_file) + plan.settings_files.length + Number(plan.empty_shell);
534
+ }
535
+ function _format_check(plan, out) {
536
+ const n = _pending_actions(plan);
537
+ _print(
538
+ out,
539
+ `\u26A0\uFE0F legacy install detected \u2014 ${n} pending action(s) (run \`agent-config migrate\` to apply, \`--dry-run\` to preview):`
540
+ );
541
+ for (const line of _plan_lines(plan)) {
542
+ _print(out, ` - ${line}`);
543
+ }
544
+ }
545
+ function _warn_on_major_mismatch(from_major, plan, out) {
546
+ if (from_major === "4" && !plan.composer) {
547
+ _print(
548
+ out,
549
+ "\u2139\uFE0F --from 4 declared but no composer.json agent-config entry found; proceeding from the detected signals."
550
+ );
551
+ } else if (from_major === "5" && !plan.npm) {
552
+ _print(
553
+ out,
554
+ "\u2139\uFE0F --from 5 declared but no package.json agent-config entry found; proceeding from the detected signals."
555
+ );
556
+ }
557
+ }
558
+ function _apply(project, out, err) {
559
+ const summary = [];
560
+ if (_strip_npm_entry(path.join(project, "package.json"))) {
561
+ summary.push(`removed ${PACKAGE_NAME_NPM} from package.json`);
562
+ }
563
+ if (_strip_composer_entry(path.join(project, "composer.json"))) {
564
+ summary.push(`removed ${PACKAGE_NAME_COMPOSER} from composer.json`);
565
+ }
566
+ const [removed_links, preserved_links] = _purge_legacy_symlinks(project);
567
+ for (const name of removed_links) {
568
+ summary.push(`removed legacy symlink ${name}`);
569
+ }
570
+ for (const name of preserved_links) {
571
+ summary.push(`preserved user-managed ${name} (review manually)`);
572
+ }
573
+ let state_summary;
574
+ try {
575
+ state_summary = _migrate_state_file(project);
576
+ } catch (exc) {
577
+ _print(err, `\u274C state migration failed: ${exc.message}`);
578
+ return 1;
579
+ }
580
+ if (state_summary) {
581
+ summary.push(state_summary);
582
+ }
583
+ for (const rel of _delete_legacy_settings(project)) {
584
+ summary.push(`deleted legacy config ${rel}`);
585
+ }
586
+ if (_remove_empty_shell(project)) {
587
+ summary.push(`removed empty ${LEGACY_AGENT_CONFIG_SHELL}/ shell`);
588
+ }
589
+ if (_update_gitignore(project)) {
590
+ summary.push(".gitignore agent-config block refreshed");
591
+ }
592
+ _print(out, "\u2705 migration complete:");
593
+ for (const line of summary) {
594
+ _print(out, ` - ${line}`);
595
+ }
596
+ _print(out, "\n Next: review the diff and commit.");
597
+ return 0;
598
+ }
599
+ function _parse(argv, out, err) {
600
+ const prog = "agent-config migrate";
601
+ const usage = `usage: ${prog} [-h] [--dry-run | --check] [--from {4,5}]
602
+ `;
603
+ const emitError = (msg) => {
604
+ err.write(usage);
605
+ err.write(`${prog}: error: ${msg}
606
+ `);
607
+ throw new ArgparseExit(2);
608
+ };
609
+ let dry_run = false;
610
+ let check = false;
611
+ let from_major = null;
612
+ let i = 0;
613
+ while (i < argv.length) {
614
+ const tok = argv[i];
615
+ if (tok === "-h" || tok === "--help") {
616
+ out.write(usage);
617
+ throw new ArgparseExit(0);
618
+ } else if (tok === "--dry-run") {
619
+ dry_run = true;
620
+ i += 1;
621
+ } else if (tok === "--check") {
622
+ check = true;
623
+ i += 1;
624
+ } else if (tok === "--from") {
625
+ const val = argv[i + 1];
626
+ if (val === void 0) {
627
+ emitError("argument --from: expected one argument");
628
+ return { dry_run, check, from_major };
629
+ }
630
+ if (val !== "4" && val !== "5") {
631
+ emitError(
632
+ `argument --from: invalid choice: '${val}' (choose from '4', '5')`
633
+ );
634
+ }
635
+ from_major = val;
636
+ i += 2;
637
+ } else if (tok.startsWith("--from=")) {
638
+ const val = tok.slice("--from=".length);
639
+ if (val !== "4" && val !== "5") {
640
+ emitError(
641
+ `argument --from: invalid choice: '${val}' (choose from '4', '5')`
642
+ );
643
+ }
644
+ from_major = val;
645
+ i += 1;
646
+ } else {
647
+ emitError(`unrecognized arguments: ${tok}`);
648
+ }
649
+ }
650
+ if (dry_run && check) {
651
+ emitError("argument --check: not allowed with argument --dry-run");
652
+ }
653
+ return { dry_run, check, from_major };
654
+ }
655
+ function main(argv = null, options = {}) {
656
+ const out = options.out ?? _stdoutSink();
657
+ const err = options.err ?? _stderrSink();
658
+ const args = _parse(argv ?? process.argv.slice(2), out, err);
659
+ const [project] = resolve_project_root(null, { cwd: options.cwd ?? null });
660
+ if (args.from_major) {
661
+ _print(out, `\u2139\uFE0F declared source major: ${args.from_major}.x`);
662
+ }
663
+ if (_detect_already_migrated(project)) {
664
+ if (args.check) {
665
+ _print(out, "\u2705 on the 6.0 layout \u2014 no migration needed.");
666
+ } else {
667
+ _print(out, "\u2705 already migrated \u2014 nothing to do.");
668
+ }
669
+ return 0;
670
+ }
671
+ const plan = _build_plan(project);
672
+ _warn_on_major_mismatch(args.from_major, plan, out);
673
+ if (args.check) {
674
+ _format_check(plan, out);
675
+ return 2;
676
+ }
677
+ if (args.dry_run) {
678
+ _format_dry_run(plan, out);
679
+ return 0;
680
+ }
681
+ return _apply(project, out, err);
682
+ }
683
+ var _bundled = true;
684
+ var _HERE = fileURLToPath(import.meta.url);
685
+ function _isCliEntry() {
686
+ if (process.argv[1] === void 0) {
687
+ return false;
688
+ }
689
+ const argvUrl = pathToFileURL(path.resolve(process.argv[1])).href;
690
+ if (import.meta.url === argvUrl) {
691
+ return true;
692
+ }
693
+ try {
694
+ const here = fs.realpathSync(fileURLToPath(import.meta.url));
695
+ const argv = fs.realpathSync(path.resolve(process.argv[1]));
696
+ return here === argv;
697
+ } catch {
698
+ return false;
699
+ }
700
+ }
701
+ if (!_bundled && (_isCliEntry() || process.argv[1] === _HERE)) {
702
+ try {
703
+ process.exitCode = main(process.argv.slice(2));
704
+ } catch (exc) {
705
+ if (exc instanceof ArgparseExit) {
706
+ process.exitCode = exc.code;
707
+ } else {
708
+ throw exc;
709
+ }
710
+ }
711
+ }
712
+
713
+ export {
714
+ main
715
+ };