@yorz/cli 0.8.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/cli/index.js +237 -102
  2. package/dist/gui/assets/{abnfDiagram-VRR7QNED-D1kFOejy.js → abnfDiagram-VRR7QNED-D-y0QKuD.js} +1 -1
  3. package/dist/gui/assets/{arc--bTdICho.js → arc-B49ieWDx.js} +1 -1
  4. package/dist/gui/assets/{architectureDiagram-ZJ3FMSHR-C3DMgcAW.js → architectureDiagram-ZJ3FMSHR-CcOou6CY.js} +1 -1
  5. package/dist/gui/assets/{blockDiagram-677ZJIJ3-BCtvFOy7.js → blockDiagram-677ZJIJ3-DY8EHGpO.js} +1 -1
  6. package/dist/gui/assets/{c4Diagram-LMCZKHZV-CDw5fv3L.js → c4Diagram-LMCZKHZV-CV8mRhow.js} +1 -1
  7. package/dist/gui/assets/channel-BakWbuVQ.js +1 -0
  8. package/dist/gui/assets/{chunk-2Q5K7J3B-DbJTSeCo.js → chunk-2Q5K7J3B-BjplUf2p.js} +1 -1
  9. package/dist/gui/assets/{chunk-32BRIVSS-BcF_P8AP.js → chunk-32BRIVSS-Dua0UKp_.js} +1 -1
  10. package/dist/gui/assets/{chunk-5VM5RSS4-CYp4dWLx.js → chunk-5VM5RSS4-Br-SORjV.js} +1 -1
  11. package/dist/gui/assets/{chunk-EX3LRPZG-BDzejC8h.js → chunk-EX3LRPZG-Dgb6iahE.js} +1 -1
  12. package/dist/gui/assets/{chunk-JWPE2WC7-Fnenn1Qc.js → chunk-JWPE2WC7-BkOQaZRq.js} +1 -1
  13. package/dist/gui/assets/{chunk-MOJQB5TN-Cx7nt_sO.js → chunk-MOJQB5TN-D1qUO9Uh.js} +1 -1
  14. package/dist/gui/assets/{chunk-RYQCIY6F-MQPZLynl.js → chunk-RYQCIY6F-CwiUC3Pd.js} +1 -1
  15. package/dist/gui/assets/{chunk-V7JOEXUC-F5RsZN0n.js → chunk-V7JOEXUC-O0VQnEjo.js} +1 -1
  16. package/dist/gui/assets/{chunk-VR4S4FIN-CoOdAASP.js → chunk-VR4S4FIN-C-iULcHx.js} +1 -1
  17. package/dist/gui/assets/{chunk-XXDRQBXY-Dp3kfiet.js → chunk-XXDRQBXY-buihollE.js} +1 -1
  18. package/dist/gui/assets/classDiagram-OUVF2IWQ-DgfCpbC5.js +1 -0
  19. package/dist/gui/assets/classDiagram-v2-EOCWNBFH-DgfCpbC5.js +1 -0
  20. package/dist/gui/assets/{cose-bilkent-JH36ORCC-PfqHyC7G.js → cose-bilkent-JH36ORCC-DJT3GZ0Y.js} +1 -1
  21. package/dist/gui/assets/{cynefin-VYW2F7L2-DerSwhBp.js → cynefin-VYW2F7L2-CUB4SFmD.js} +1 -1
  22. package/dist/gui/assets/{cynefinDiagram-TSTJHNR4-BwakZjCU.js → cynefinDiagram-TSTJHNR4-Dt0_fxzu.js} +1 -1
  23. package/dist/gui/assets/{dagre-VKFMJZFB-Bqgor74s.js → dagre-VKFMJZFB-BU2VgIkF.js} +1 -1
  24. package/dist/gui/assets/{diagram-FQU43EPY-DgyWxpcU.js → diagram-FQU43EPY-CpRyd1t3.js} +1 -1
  25. package/dist/gui/assets/{diagram-G47NLZAW-DwvD_Up0.js → diagram-G47NLZAW-CcJkOrvN.js} +1 -1
  26. package/dist/gui/assets/{diagram-NH7WQ7WH-DSimddOu.js → diagram-NH7WQ7WH-BcWa9fg4.js} +1 -1
  27. package/dist/gui/assets/{diagram-OA4YK3LP-CrBUd7XP.js → diagram-OA4YK3LP-Clu9LYE6.js} +1 -1
  28. package/dist/gui/assets/{diagram-WEI45ONY-BWgcRZqn.js → diagram-WEI45ONY-BKt73qmr.js} +1 -1
  29. package/dist/gui/assets/{ebnfDiagram-CCIWWBDH-g9dEaUVe.js → ebnfDiagram-CCIWWBDH-ycI3xDTZ.js} +1 -1
  30. package/dist/gui/assets/{erDiagram-Q63AITRT-DhYVc7YD.js → erDiagram-Q63AITRT-CJf0jIvL.js} +1 -1
  31. package/dist/gui/assets/{flowDiagram-23GEKE2U-COeJThES.js → flowDiagram-23GEKE2U-8X7ZYojT.js} +1 -1
  32. package/dist/gui/assets/{ganttDiagram-NO4QXBWP-DJxQzqsI.js → ganttDiagram-NO4QXBWP-DsGJIvEc.js} +1 -1
  33. package/dist/gui/assets/{gitGraphDiagram-IHSO6WYX-CC_xIkVG.js → gitGraphDiagram-IHSO6WYX-Dg-PnhMR.js} +1 -1
  34. package/dist/gui/assets/{index-BzxGbxnX.css → index-DGSN0uvJ.css} +1 -1
  35. package/dist/gui/assets/{index-tquwDQwL.js → index-DIKCFt79.js} +20 -20
  36. package/dist/gui/assets/{infoDiagram-FWYZ7A6U-C6FK6dRz.js → infoDiagram-FWYZ7A6U-CX-PGRjw.js} +1 -1
  37. package/dist/gui/assets/{ishikawaDiagram-FXEZZL3T-D7b3GjN0.js → ishikawaDiagram-FXEZZL3T-BGq-1WGF.js} +1 -1
  38. package/dist/gui/assets/{journeyDiagram-5HDEW3XC-Ct0_MZXS.js → journeyDiagram-5HDEW3XC-CX7J6QLx.js} +1 -1
  39. package/dist/gui/assets/{kanban-definition-HUTT4EX6-M4nszR7h.js → kanban-definition-HUTT4EX6-XcUXgRy6.js} +1 -1
  40. package/dist/gui/assets/{linear-CGUJayt8.js → linear-D-w3YyOR.js} +1 -1
  41. package/dist/gui/assets/{mermaid.core-DpiXCPQI.js → mermaid.core-BjB4Bulu.js} +4 -4
  42. package/dist/gui/assets/{mindmap-definition-LN4V7U3C-CBbqzgM2.js → mindmap-definition-LN4V7U3C-D2kDYOXu.js} +1 -1
  43. package/dist/gui/assets/{pegDiagram-2B236MQR-BW9OSYgR.js → pegDiagram-2B236MQR-C79JhnNB.js} +1 -1
  44. package/dist/gui/assets/{pieDiagram-ENE6RG2P-CT3MdE-x.js → pieDiagram-ENE6RG2P-CbLYFwp4.js} +1 -1
  45. package/dist/gui/assets/{quadrantDiagram-ABIIQ3AL-BAqDSslO.js → quadrantDiagram-ABIIQ3AL-BXNa6Xix.js} +1 -1
  46. package/dist/gui/assets/{railroadDiagram-RFXS5EU6-BjxuOun7.js → railroadDiagram-RFXS5EU6-CG8ojk-9.js} +1 -1
  47. package/dist/gui/assets/{requirementDiagram-TGXJPOKE-bqwQ3Xy2.js → requirementDiagram-TGXJPOKE-Ddn0mejD.js} +1 -1
  48. package/dist/gui/assets/{sankeyDiagram-HTMAVEWB-D5UFHu3G.js → sankeyDiagram-HTMAVEWB-DXVSB34u.js} +1 -1
  49. package/dist/gui/assets/{sequenceDiagram-DBY2YBRQ-BimXCn08.js → sequenceDiagram-DBY2YBRQ-B00FxwKQ.js} +1 -1
  50. package/dist/gui/assets/{sizeCapture-X5ZJPWSS-3iod82ny.js → sizeCapture-X5ZJPWSS-BUiEsqdO.js} +1 -1
  51. package/dist/gui/assets/{stateDiagram-2N3HPSRC-BCkRUWaU.js → stateDiagram-2N3HPSRC-DflPz4MT.js} +1 -1
  52. package/dist/gui/assets/stateDiagram-v2-6OUMAXLB-DQohEYjS.js +1 -0
  53. package/dist/gui/assets/{swimlanes-5IMT3BWC-D7XMYBp1.js → swimlanes-5IMT3BWC-yL7Pms6k.js} +2 -2
  54. package/dist/gui/assets/swimlanesDiagram-G3AALYLV-CUZb2EKw.js +8 -0
  55. package/dist/gui/assets/{timeline-definition-FHXFAJF6-D9U9I24L.js → timeline-definition-FHXFAJF6--V8N1aYE.js} +1 -1
  56. package/dist/gui/assets/{vennDiagram-L72KCM5P-DKs7jWNI.js → vennDiagram-L72KCM5P-CjlyPLPm.js} +1 -1
  57. package/dist/gui/assets/{wardleyDiagram-EHGQE667-CLvHSSW6.js → wardleyDiagram-EHGQE667-C99qPu9U.js} +1 -1
  58. package/dist/gui/assets/{xychartDiagram-FW5EYKEG-V0U7x5OK.js → xychartDiagram-FW5EYKEG-DeUNfALY.js} +1 -1
  59. package/dist/gui/index.html +24 -8
  60. package/package.json +1 -1
  61. package/dist/gui/assets/channel-Zv7U9soI.js +0 -1
  62. package/dist/gui/assets/classDiagram-OUVF2IWQ-DRHl_SaL.js +0 -1
  63. package/dist/gui/assets/classDiagram-v2-EOCWNBFH-DRHl_SaL.js +0 -1
  64. package/dist/gui/assets/stateDiagram-v2-6OUMAXLB-7yy6idF2.js +0 -1
  65. package/dist/gui/assets/swimlanesDiagram-G3AALYLV-DGa9rk3s.js +0 -8
package/dist/cli/index.js CHANGED
@@ -23,7 +23,7 @@ import { createOpencode } from "@opencode-ai/sdk";
23
23
  import { createInterface as createInterface$1 } from "node:readline/promises";
24
24
  import MarkdownIt from "markdown-it";
25
25
  const name = "@yorz/cli";
26
- const version = "0.8.0";
26
+ const version = "0.8.1";
27
27
  const type = "module";
28
28
  const description = "";
29
29
  const bin = { "yorz": "./dist/cli/index.js" };
@@ -373,10 +373,19 @@ function normalizeWorktree(value) {
373
373
  if (cleanSlug) meta.cleanSlug = cleanSlug;
374
374
  return meta;
375
375
  }
376
- function generateProjectId(absPath) {
377
- const base = basename$1(absPath);
378
- const slug = slugify(base) || "proj";
376
+ const WORKTREE_DIR_SUFFIX = ".wt";
377
+ const MAX_WORKTREE_NESTING = 4;
378
+ function resolveWorktreeMainPath(absPath) {
379
+ const parent = dirname(absPath);
380
+ const parentName = basename$1(parent);
381
+ if (!parentName.endsWith(WORKTREE_DIR_SUFFIX) || parentName === WORKTREE_DIR_SUFFIX) return null;
382
+ return join(dirname(parent), parentName.slice(0, -WORKTREE_DIR_SUFFIX.length));
383
+ }
384
+ function generateProjectId(absPath, depth = 0) {
379
385
  const hash = createHash("sha256").update(absPath).digest("hex").slice(0, 6);
386
+ const mainPath = depth < MAX_WORKTREE_NESTING ? resolveWorktreeMainPath(absPath) : null;
387
+ if (mainPath) return `${generateProjectId(mainPath, depth + 1)}_wt-${hash}`;
388
+ const slug = slugify(basename$1(absPath)) || "proj";
380
389
  return `${slug}-${hash}`;
381
390
  }
382
391
  function slugify(text) {
@@ -1201,14 +1210,19 @@ function skillRef(skillName, env = process.env) {
1201
1210
  }
1202
1211
  const METRICS_DIR_NAME = "metrics";
1203
1212
  const TELEMETRY_FILE_NAME = "telemetry.jsonl";
1204
- const PROJECT_META_FILE_NAME = "project.json";
1205
- const DEFAULT_TELEMETRY_MAX_BYTES = 5 * 1024 * 1024;
1206
- const DEFAULT_TELEMETRY_MAX_ARCHIVES = 2;
1213
+ const PROJECTS_INDEX_FILE_NAME = "projects.json";
1214
+ const TELEMETRY_RETENTION_DAYS = 365;
1215
+ const TELEMETRY_RETENTION_MS = TELEMETRY_RETENTION_DAYS * 24 * 60 * 60 * 1e3;
1216
+ const TELEMETRY_MAX_BYTES = Number.POSITIVE_INFINITY;
1217
+ const TELEMETRY_MAX_ARCHIVES = 0;
1207
1218
  function resolveMetricsDir(env = process.env) {
1208
1219
  return join(resolveGlobalConfigDir(env), METRICS_DIR_NAME);
1209
1220
  }
1210
- function resolveProjectMetricsDir(projectRoot, env = process.env) {
1211
- return join(resolveMetricsDir(env), generateProjectId(resolve(projectRoot)));
1221
+ function resolveTelemetryFile(env = process.env) {
1222
+ return join(resolveMetricsDir(env), TELEMETRY_FILE_NAME);
1223
+ }
1224
+ function resolveProjectsIndexFile(env = process.env) {
1225
+ return join(resolveMetricsDir(env), PROJECTS_INDEX_FILE_NAME);
1212
1226
  }
1213
1227
  function findProjectRoot(startDir) {
1214
1228
  let dir = resolve(startDir);
@@ -1267,27 +1281,38 @@ function compact(snapshot) {
1267
1281
  function isEmpty(snapshot) {
1268
1282
  return Object.keys(snapshot).length === 0;
1269
1283
  }
1270
- const TELEMETRY_SCHEMA_VERSION = 1;
1284
+ const TELEMETRY_SCHEMA_VERSION = 2;
1271
1285
  function isTelemetryEnabled(env = process.env) {
1272
1286
  const raw = env.YORZ_TELEMETRY?.trim().toLowerCase();
1273
1287
  if (!raw) return true;
1274
1288
  return !["off", "0", "false", "no", "disabled"].includes(raw);
1275
1289
  }
1290
+ const sinks = /* @__PURE__ */ new Map();
1291
+ const indexQueues = /* @__PURE__ */ new Map();
1292
+ function enqueueIndexUpdate(file, task) {
1293
+ const next = (indexQueues.get(file) ?? Promise.resolve()).then(task).catch(() => {
1294
+ });
1295
+ indexQueues.set(file, next);
1296
+ }
1297
+ function getSink(dir) {
1298
+ let sink = sinks.get(dir);
1299
+ if (!sink) {
1300
+ sink = new RotatingFileSink(dir, TELEMETRY_FILE_NAME, TELEMETRY_MAX_BYTES, TELEMETRY_MAX_ARCHIVES);
1301
+ sinks.set(dir, sink);
1302
+ }
1303
+ return sink;
1304
+ }
1276
1305
  class TelemetryRecorder {
1277
- constructor(projectRoot, projectId, dir, enabled) {
1306
+ constructor(projectRoot, projectId, dir, enabled, indexFile) {
1278
1307
  this.projectRoot = projectRoot;
1279
1308
  this.projectId = projectId;
1280
1309
  this.dir = dir;
1281
1310
  this.enabled = enabled;
1282
- this.sink = enabled ? new RotatingFileSink(
1283
- dir,
1284
- TELEMETRY_FILE_NAME,
1285
- DEFAULT_TELEMETRY_MAX_BYTES,
1286
- DEFAULT_TELEMETRY_MAX_ARCHIVES
1287
- ) : null;
1311
+ this.indexFile = indexFile;
1312
+ this.sink = enabled ? getSink(dir) : null;
1288
1313
  }
1289
1314
  sink;
1290
- metaWritten = false;
1315
+ indexWritten = false;
1291
1316
  get filePath() {
1292
1317
  return join(this.dir, TELEMETRY_FILE_NAME);
1293
1318
  }
@@ -1298,7 +1323,7 @@ class TelemetryRecorder {
1298
1323
  try {
1299
1324
  const envelope = {
1300
1325
  v: TELEMETRY_SCHEMA_VERSION,
1301
- ts: nowStamp(),
1326
+ ts: Date.now(),
1302
1327
  event,
1303
1328
  projectId: this.projectId,
1304
1329
  ...payload
@@ -1309,29 +1334,33 @@ class TelemetryRecorder {
1309
1334
  return;
1310
1335
  }
1311
1336
  this.sink.write(line);
1312
- this.ensureMeta();
1337
+ this.ensureIndexed();
1313
1338
  }
1314
1339
  /** Resolve once every queued line has hit the disk (tests / shutdown). */
1315
1340
  async flush() {
1316
1341
  await this.sink?.flush();
1317
- }
1318
- /** Write the id → absolute path sidecar once per process. Best-effort. */
1319
- ensureMeta() {
1320
- if (this.metaWritten || !this.sink) return;
1321
- this.metaWritten = true;
1322
- const meta = {
1323
- id: this.projectId,
1324
- path: this.projectRoot,
1325
- firstSeenAt: nowStamp()
1326
- };
1327
- void (async () => {
1342
+ await indexQueues.get(this.indexFile);
1343
+ }
1344
+ /** Merge this project into `projects.json` once per process. Best-effort. */
1345
+ ensureIndexed() {
1346
+ if (this.indexWritten || !this.sink) return;
1347
+ this.indexWritten = true;
1348
+ const { projectId, projectRoot, indexFile } = this;
1349
+ enqueueIndexUpdate(indexFile, async () => {
1350
+ let index = {};
1328
1351
  try {
1329
- await mkdir(this.dir, { recursive: true });
1330
- await writeFile(join(this.dir, PROJECT_META_FILE_NAME), `${JSON.stringify(meta, null, 2)}
1331
- `);
1352
+ index = JSON.parse(await readFile(indexFile, "utf8"));
1332
1353
  } catch {
1333
1354
  }
1334
- })();
1355
+ const existing = index[projectId];
1356
+ if (existing?.path === projectRoot) return;
1357
+ index[projectId] = {
1358
+ path: projectRoot,
1359
+ firstSeenAt: existing?.firstSeenAt ?? Date.now()
1360
+ };
1361
+ await writeFile(indexFile, `${JSON.stringify(index, null, 2)}
1362
+ `);
1363
+ });
1335
1364
  }
1336
1365
  }
1337
1366
  const recorders = /* @__PURE__ */ new Map();
@@ -1342,17 +1371,13 @@ function getTelemetry(projectRoot, env = process.env) {
1342
1371
  const recorder = new TelemetryRecorder(
1343
1372
  root,
1344
1373
  generateProjectId(root),
1345
- resolveProjectMetricsDir(root, env),
1346
- isTelemetryEnabled(env)
1374
+ resolveMetricsDir(env),
1375
+ isTelemetryEnabled(env),
1376
+ resolveProjectsIndexFile(env)
1347
1377
  );
1348
1378
  recorders.set(root, recorder);
1349
1379
  return recorder;
1350
1380
  }
1351
- function nowStamp(date = /* @__PURE__ */ new Date()) {
1352
- const pad = (n) => String(n).padStart(2, "0");
1353
- const ymd = `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
1354
- return `${ymd} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
1355
- }
1356
1381
  const TASK_LINE = /^- \[( |x|X)\]/gm;
1357
1382
  function snapshotSpec(detail) {
1358
1383
  if (!detail) return null;
@@ -1395,6 +1420,124 @@ function trackSpecStage(opts) {
1395
1420
  })();
1396
1421
  });
1397
1422
  }
1423
+ const RETIRED_EVENTS = /* @__PURE__ */ new Set(["git.op", "spec.change"]);
1424
+ async function initTelemetryStore(opts = {}) {
1425
+ const env = opts.env ?? process.env;
1426
+ const now = opts.now ?? Date.now();
1427
+ const cutoff = now - (opts.retentionMs ?? TELEMETRY_RETENTION_MS);
1428
+ const stats = { migrated: 0, kept: 0, dropped: 0, legacyDirs: 0 };
1429
+ const dir = resolveMetricsDir(env);
1430
+ if (!existsSync(dir)) return stats;
1431
+ const rows = [];
1432
+ collect(await readLines(resolveTelemetryFile(env)), cutoff, rows, stats);
1433
+ const migratedBefore = rows.length;
1434
+ await migrateLegacyDirs(dir, env, cutoff, rows, stats);
1435
+ stats.migrated = rows.length - migratedBefore;
1436
+ rows.sort((a, b) => a.ts - b.ts);
1437
+ stats.kept = rows.length;
1438
+ if (rows.length === 0 && stats.dropped === 0) return stats;
1439
+ try {
1440
+ await writeAtomic(resolveTelemetryFile(env), rows.map((r) => `${JSON.stringify(r)}
1441
+ `).join(""));
1442
+ } catch {
1443
+ }
1444
+ return stats;
1445
+ }
1446
+ async function migrateLegacyDirs(metricsDir, env, cutoff, rows, stats) {
1447
+ let entries;
1448
+ try {
1449
+ entries = (await readdir(metricsDir, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => e.name);
1450
+ } catch {
1451
+ return;
1452
+ }
1453
+ if (entries.length === 0) return;
1454
+ const index = await readIndex(env);
1455
+ for (const projectId of entries) {
1456
+ const legacyDir = join(metricsDir, projectId);
1457
+ for (const file of await legacyFiles(legacyDir)) {
1458
+ collect(await readLines(file), cutoff, rows, stats, projectId);
1459
+ }
1460
+ const meta = await readLegacyMeta(legacyDir);
1461
+ if (meta && !index[projectId]) {
1462
+ index[projectId] = { path: meta.path, firstSeenAt: meta.firstSeenAt };
1463
+ }
1464
+ try {
1465
+ await rm(legacyDir, { recursive: true, force: true });
1466
+ stats.legacyDirs += 1;
1467
+ } catch {
1468
+ }
1469
+ }
1470
+ await writeIndex(env, index);
1471
+ }
1472
+ async function legacyFiles(dir) {
1473
+ try {
1474
+ return (await readdir(dir)).filter((name2) => name2 === TELEMETRY_FILE_NAME || name2.startsWith(`${TELEMETRY_FILE_NAME}.`)).map((name2) => join(dir, name2));
1475
+ } catch {
1476
+ return [];
1477
+ }
1478
+ }
1479
+ async function readLegacyMeta(dir) {
1480
+ try {
1481
+ const raw = JSON.parse(await readFile(join(dir, "project.json"), "utf8"));
1482
+ if (!raw.path) return null;
1483
+ return { path: raw.path, firstSeenAt: parseTs(raw.firstSeenAt) ?? 0 };
1484
+ } catch {
1485
+ return null;
1486
+ }
1487
+ }
1488
+ function collect(lines, cutoff, out, stats, fallbackProjectId) {
1489
+ for (const line of lines) {
1490
+ let ev;
1491
+ try {
1492
+ ev = JSON.parse(line);
1493
+ } catch {
1494
+ stats.dropped += 1;
1495
+ continue;
1496
+ }
1497
+ const ts = parseTs(ev.ts);
1498
+ const event = typeof ev.event === "string" ? ev.event : "";
1499
+ const projectId = typeof ev.projectId === "string" ? ev.projectId : fallbackProjectId;
1500
+ if (ts === null || ts < cutoff || !event || !projectId || RETIRED_EVENTS.has(event)) {
1501
+ stats.dropped += 1;
1502
+ continue;
1503
+ }
1504
+ out.push({ ...ev, v: TELEMETRY_SCHEMA_VERSION, ts, event, projectId });
1505
+ }
1506
+ }
1507
+ function parseTs(value) {
1508
+ if (typeof value === "number") return Number.isFinite(value) ? value : null;
1509
+ if (typeof value !== "string") return null;
1510
+ const ms = Date.parse(value.includes("T") ? value : value.replace(" ", "T"));
1511
+ return Number.isNaN(ms) ? null : ms;
1512
+ }
1513
+ async function readLines(file) {
1514
+ try {
1515
+ return (await readFile(file, "utf8")).split("\n").filter((l) => l.trim());
1516
+ } catch {
1517
+ return [];
1518
+ }
1519
+ }
1520
+ async function readIndex(env) {
1521
+ try {
1522
+ return JSON.parse(await readFile(resolveProjectsIndexFile(env), "utf8"));
1523
+ } catch {
1524
+ return {};
1525
+ }
1526
+ }
1527
+ async function writeIndex(env, index) {
1528
+ if (Object.keys(index).length === 0) return;
1529
+ try {
1530
+ await writeFile(resolveProjectsIndexFile(env), `${JSON.stringify(index, null, 2)}
1531
+ `);
1532
+ } catch {
1533
+ }
1534
+ }
1535
+ async function writeAtomic(file, content) {
1536
+ const tmp = `${file}.tmp`;
1537
+ await mkdir(join(file, ".."), { recursive: true });
1538
+ await writeFile(tmp, content, "utf8");
1539
+ await rename(tmp, file);
1540
+ }
1398
1541
  function createSpecsRoutes(resolveProject) {
1399
1542
  const app = new Hono();
1400
1543
  const need = async (c) => {
@@ -2305,27 +2448,16 @@ function assertSafeRelativePath(cwd, p) {
2305
2448
  }
2306
2449
  return p;
2307
2450
  }
2308
- function recordGitOp(cwd, args, startedAt, ok, code) {
2309
- getTelemetry(cwd).record("git.op", {
2310
- op: args[0] ?? "unknown",
2311
- ok,
2312
- exitCode: code,
2313
- durMs: Date.now() - startedAt
2314
- });
2315
- }
2316
2451
  async function runGit(cwd, args) {
2317
- const startedAt = Date.now();
2318
2452
  try {
2319
2453
  const result = await execFileWithoutWindow("git", args, {
2320
2454
  cwd,
2321
2455
  encoding: "utf8",
2322
2456
  maxBuffer: 16 * 1024 * 1024
2323
2457
  });
2324
- recordGitOp(cwd, args, startedAt, true, 0);
2325
2458
  return { stdout: result.stdout, stderr: result.stderr };
2326
2459
  } catch (err) {
2327
2460
  const e = err;
2328
- recordGitOp(cwd, args, startedAt, false, typeof e.code === "number" ? e.code : void 0);
2329
2461
  if (e.code === "ENOENT") {
2330
2462
  throw new GitError("git_missing", "git not found on PATH");
2331
2463
  }
@@ -2336,23 +2468,19 @@ async function runGitChecked(cwd, args) {
2336
2468
  return runGit(cwd, args);
2337
2469
  }
2338
2470
  async function runGitRaw(cwd, args) {
2339
- const startedAt = Date.now();
2340
2471
  try {
2341
2472
  const result = await execFileWithoutWindow("git", args, {
2342
2473
  cwd,
2343
2474
  encoding: "utf8",
2344
2475
  maxBuffer: 16 * 1024 * 1024
2345
2476
  });
2346
- recordGitOp(cwd, args, startedAt, true, 0);
2347
2477
  return { stdout: result.stdout, stderr: result.stderr, code: 0 };
2348
2478
  } catch (err) {
2349
2479
  const e = err;
2350
2480
  if (e.code === "ENOENT") {
2351
- recordGitOp(cwd, args, startedAt, false);
2352
2481
  throw new GitError("git_missing", "git not found on PATH");
2353
2482
  }
2354
2483
  const code = typeof e.code === "number" ? e.code : 1;
2355
- recordGitOp(cwd, args, startedAt, false, code);
2356
2484
  return { stdout: e.stdout ?? "", stderr: e.stderr ?? e.message ?? "", code };
2357
2485
  }
2358
2486
  }
@@ -2499,7 +2627,12 @@ async function currentBranch(cwd) {
2499
2627
  async function listBranches(cwd) {
2500
2628
  const [current, branchesResult] = await Promise.all([
2501
2629
  currentBranch(cwd),
2502
- runGit(cwd, ["branch", "--format=%(refname:short)"])
2630
+ runGit(cwd, [
2631
+ "for-each-ref",
2632
+ "--sort=-committerdate",
2633
+ "--format=%(refname:short)",
2634
+ "refs/heads"
2635
+ ])
2503
2636
  ]);
2504
2637
  const branches = branchesResult.stdout.split("\n").map((line) => line.trim()).filter(Boolean);
2505
2638
  return { current, branches };
@@ -5234,7 +5367,7 @@ function parseCommitLines(stdout) {
5234
5367
  function renderConflictSpec(args) {
5235
5368
  const { branch, report, now } = args;
5236
5369
  const today = `${now.getFullYear()}-${pad2(now.getMonth() + 1)}-${pad2(now.getDate())}`;
5237
- const nowStamp2 = `${today} ${pad2(now.getHours())}:${pad2(now.getMinutes())}:${pad2(now.getSeconds())}`;
5370
+ const nowStamp = `${today} ${pad2(now.getHours())}:${pad2(now.getMinutes())}:${pad2(now.getSeconds())}`;
5238
5371
  const fileLines = report.files.length ? report.files.map((f) => `- \`${f}\``).join("\n") : "- (无 — 合并失败但未列出冲突文件,请人工核查)";
5239
5372
  const commitBlocks = report.files.length ? report.files.map((f) => {
5240
5373
  const commits = report.commitsByFile[f] ?? [];
@@ -5304,7 +5437,7 @@ _暂无_
5304
5437
  "---",
5305
5438
  "stage: plan",
5306
5439
  "last_action: 由 worktree 合并冲突自动生成",
5307
- `updated_at: '${nowStamp2}'`,
5440
+ `updated_at: '${nowStamp}'`,
5308
5441
  `summary: 解决 ${branch} 合并到主项目时产生的 ${report.files.length} 个冲突文件`,
5309
5442
  "---",
5310
5443
  ""
@@ -5849,7 +5982,6 @@ const watcherLog = () => getLogger().child("watcher");
5849
5982
  const UNLINK_SETTLE_MS = 80;
5850
5983
  class SpecWatcher {
5851
5984
  root;
5852
- cwd;
5853
5985
  unlinkSettleMs;
5854
5986
  detailListeners = /* @__PURE__ */ new Map();
5855
5987
  listListeners = /* @__PURE__ */ new Set();
@@ -5860,7 +5992,6 @@ class SpecWatcher {
5860
5992
  watcher = null;
5861
5993
  constructor(opts) {
5862
5994
  this.root = opts.specsDir ?? join(opts.cwd, ".yorz", "specs");
5863
- this.cwd = opts.cwd;
5864
5995
  this.unlinkSettleMs = opts.unlinkSettleMs ?? UNLINK_SETTLE_MS;
5865
5996
  }
5866
5997
  async start() {
@@ -5954,7 +6085,6 @@ class SpecWatcher {
5954
6085
  this.pendingUnlinks.set(id, timer);
5955
6086
  }
5956
6087
  emit(id, evt, mtimeMs) {
5957
- getTelemetry(this.cwd).record("spec.change", { specId: id, kind: evt, mtimeMs });
5958
6088
  for (const cb of this.detailListeners.get(id) ?? []) cb(evt, mtimeMs);
5959
6089
  for (const cb of this.listListeners) cb();
5960
6090
  }
@@ -7810,6 +7940,12 @@ async function start(opts = {}) {
7810
7940
  } catch {
7811
7941
  }
7812
7942
  }
7943
+ try {
7944
+ const stats = await initTelemetryStore();
7945
+ log$1().info("telemetry store ready", { ...stats });
7946
+ } catch (err) {
7947
+ log$1().warn("telemetry housekeeping failed", { err });
7948
+ }
7813
7949
  const projects = await registry.list();
7814
7950
  const systemNotifications = new SystemNotificationCenter();
7815
7951
  systemNotifications.startVersionChecks();
@@ -9536,21 +9672,23 @@ async function recordLintRun(cwd, payload) {
9536
9672
  }
9537
9673
  const UNATTRIBUTED = "(no spec)";
9538
9674
  async function runMetrics(opts) {
9539
- const dirs = await resolveTargetDirs(opts);
9540
- if (dirs.length === 0) {
9541
- process.stderr.write(
9542
- "no telemetry found — run a dispatch first, or pass --project <id|path> / --all\n"
9543
- );
9675
+ const file = resolveTelemetryFile();
9676
+ if (!existsSync(file)) {
9677
+ process.stderr.write("no telemetry found — run a dispatch first\n");
9544
9678
  return { exitCode: 1, summary: emptySummary() };
9545
9679
  }
9680
+ const filter = resolveProjectFilter(opts);
9546
9681
  const summary = emptySummary();
9547
- for (const dir of dirs) {
9548
- summary.projects.push(await projectLabel(dir));
9549
- for (const file of await telemetryFiles(dir)) {
9550
- summary.files.push(file);
9551
- await consumeFile(file, opts.since, summary);
9552
- }
9682
+ summary.files.push(file);
9683
+ await consumeFile(file, opts, filter, summary);
9684
+ if (summary.lines === 0) {
9685
+ process.stderr.write(
9686
+ filter ? `no telemetry for project ${filter} — pass --project <id|path> / --all
9687
+ ` : "no telemetry matched the given filters\n"
9688
+ );
9689
+ return { exitCode: 1, summary };
9553
9690
  }
9691
+ summary.projects = await projectLabels(summary.projects);
9554
9692
  summary.specs.sort((a, b) => b.costUsd - a.costUsd || b.turns - a.turns);
9555
9693
  if (opts.format === "json") {
9556
9694
  process.stdout.write(`${JSON.stringify(summary, null, 2)}
@@ -9560,45 +9698,36 @@ async function runMetrics(opts) {
9560
9698
  }
9561
9699
  return { exitCode: 0, summary };
9562
9700
  }
9563
- async function resolveTargetDirs(opts) {
9564
- const metricsDir = resolveMetricsDir();
9565
- if (opts.all) {
9566
- if (!existsSync(metricsDir)) return [];
9567
- const entries = await readdir(metricsDir, { withFileTypes: true });
9568
- return entries.filter((e) => e.isDirectory()).map((e) => join(metricsDir, e.name));
9569
- }
9701
+ function resolveProjectFilter(opts) {
9702
+ if (opts.all) return null;
9570
9703
  if (opts.project) {
9571
- const dir2 = isAbsolute(opts.project) ? resolveProjectMetricsDir(opts.project) : join(metricsDir, opts.project);
9572
- return existsSync(dir2) ? [dir2] : [];
9704
+ return isAbsolute(opts.project) ? generateProjectId(resolve(opts.project)) : opts.project;
9573
9705
  }
9574
9706
  const root = findProjectRoot(opts.cwd);
9575
- if (!root) return [];
9576
- const dir = resolveProjectMetricsDir(root);
9577
- return existsSync(dir) ? [dir] : [];
9578
- }
9579
- async function telemetryFiles(dir) {
9580
- if (!existsSync(dir)) return [];
9581
- const entries = await readdir(dir);
9582
- const archives = entries.filter((name2) => name2.startsWith(`${TELEMETRY_FILE_NAME}.`)).sort((a, b) => Number(b.split(".").pop()) - Number(a.split(".").pop())).map((name2) => join(dir, name2));
9583
- const current = join(dir, TELEMETRY_FILE_NAME);
9584
- return existsSync(current) ? [...archives, current] : archives;
9585
- }
9586
- async function projectLabel(dir) {
9707
+ return root ? generateProjectId(root) : null;
9708
+ }
9709
+ async function projectLabels(ids) {
9710
+ let index = {};
9587
9711
  try {
9588
- const raw = await readFile(join(dir, PROJECT_META_FILE_NAME), "utf8");
9589
- const meta = JSON.parse(raw);
9590
- return meta.path ? `${meta.id ?? "?"} (${meta.path})` : meta.id ?? dir;
9712
+ index = JSON.parse(await readFile(resolveProjectsIndexFile(), "utf8"));
9591
9713
  } catch {
9592
- return dir;
9593
9714
  }
9715
+ return ids.map((id) => index[id]?.path ? `${id} (${index[id].path})` : id);
9594
9716
  }
9595
- async function consumeFile(file, since, out) {
9717
+ function sinceMs(since) {
9718
+ if (!since) return null;
9719
+ const ms = Date.parse(`${since}T00:00:00`);
9720
+ return Number.isNaN(ms) ? null : ms;
9721
+ }
9722
+ async function consumeFile(file, opts, filter, out) {
9596
9723
  let raw;
9597
9724
  try {
9598
9725
  raw = await readFile(file, "utf8");
9599
9726
  } catch {
9600
9727
  return;
9601
9728
  }
9729
+ const from = sinceMs(opts.since);
9730
+ const seenProjects = /* @__PURE__ */ new Set();
9602
9731
  for (const line of raw.split("\n")) {
9603
9732
  if (!line.trim()) continue;
9604
9733
  let ev;
@@ -9608,8 +9737,14 @@ async function consumeFile(file, since, out) {
9608
9737
  out.skipped += 1;
9609
9738
  continue;
9610
9739
  }
9611
- const ts = typeof ev.ts === "string" ? ev.ts : "";
9612
- if (since && ts.slice(0, 10) < since) continue;
9740
+ const projectId = typeof ev.projectId === "string" ? ev.projectId : "";
9741
+ if (filter && projectId !== filter) continue;
9742
+ const ts = parseTs(ev.ts);
9743
+ if (from !== null && (ts === null || ts < from)) continue;
9744
+ if (projectId && !seenProjects.has(projectId)) {
9745
+ seenProjects.add(projectId);
9746
+ out.projects.push(projectId);
9747
+ }
9613
9748
  out.lines += 1;
9614
9749
  const event = typeof ev.event === "string" ? ev.event : "unknown";
9615
9750
  out.eventCounts[event] = (out.eventCounts[event] ?? 0) + 1;
@@ -1 +1 @@
1
- import{g as p,r as u,d as a}from"./chunk-MOJQB5TN-Cx7nt_sO.js";import{p as f}from"./chunk-JWPE2WC7-Fnenn1Qc.js";import{_ as n,l as o}from"./mermaid.core-DpiXCPQI.js";import{M as c,b as d}from"./cynefin-VYW2F7L2-DerSwhBp.js";import"./index-tquwDQwL.js";var v=d().RailroadAbnf.parser.LangiumParser,i=n(e=>{const r=e.alternatives.map(g);return r.length===1?r[0]:{type:"choice",alternatives:r}},"transformAlternation"),g=n(e=>{const r=e.elements.map(y);return r.length===1?r[0]:{type:"sequence",elements:r}},"transformConcatenation"),b=n(e=>{if(e.includes("*")){const[t,s]=e.split("*"),l=t?parseInt(t,10):0,m=s?parseInt(s,10):1/0;return{min:l,max:m}}const r=parseInt(e,10);return{min:r,max:r}},"parseRepeat"),y=n(e=>{const r=A(e.primary);if(!e.repeat)return r;const{min:t,max:s}=b(e.repeat);return t===0&&s===1?{type:"optional",element:r}:{type:"repetition",element:r,min:t,max:s}},"transformElement"),A=n(e=>{switch(e.$type){case"AbnfStringLiteral":return{type:"terminal",value:e.value};case"AbnfNumVal":return{type:"terminal",value:e.value};case"AbnfRuleName":return{type:"nonterminal",name:e.name};case"AbnfGroup":return i(e.element);case"AbnfOptionalGroup":return{type:"optional",element:i(e.element)};default:throw new Error(`Unsupported ABNF primary node: ${e.$type}`)}},"transformPrimary"),P=n(e=>({name:e.name,definition:i(e.definition)}),"transformRule"),h=n(e=>{f(e,a),e.title&&a.setTitle(e.title),e.rules.map(r=>a.addRule(P(r)))},"populateDb"),R={parse:n(e=>{a.clear(),o.debug("[ABNF Parser] Starting Langium parse");const r=v.parse(e);if(r.lexerErrors.length>0||r.parserErrors.length>0)throw new c(r);const t=r.value;o.debug("[ABNF Parser] Parsed rules:",t.rules.length),h(t),o.debug("[ABNF Parser] Parse complete")},"parse"),parser:{yy:a}},B={parser:R,db:a,renderer:u,styles:p};export{B as diagram};
1
+ import{g as p,r as u,d as a}from"./chunk-MOJQB5TN-D1qUO9Uh.js";import{p as f}from"./chunk-JWPE2WC7-BkOQaZRq.js";import{_ as n,l as o}from"./mermaid.core-BjB4Bulu.js";import{M as c,b as d}from"./cynefin-VYW2F7L2-CUB4SFmD.js";import"./index-DIKCFt79.js";var v=d().RailroadAbnf.parser.LangiumParser,i=n(e=>{const r=e.alternatives.map(g);return r.length===1?r[0]:{type:"choice",alternatives:r}},"transformAlternation"),g=n(e=>{const r=e.elements.map(y);return r.length===1?r[0]:{type:"sequence",elements:r}},"transformConcatenation"),b=n(e=>{if(e.includes("*")){const[t,s]=e.split("*"),l=t?parseInt(t,10):0,m=s?parseInt(s,10):1/0;return{min:l,max:m}}const r=parseInt(e,10);return{min:r,max:r}},"parseRepeat"),y=n(e=>{const r=A(e.primary);if(!e.repeat)return r;const{min:t,max:s}=b(e.repeat);return t===0&&s===1?{type:"optional",element:r}:{type:"repetition",element:r,min:t,max:s}},"transformElement"),A=n(e=>{switch(e.$type){case"AbnfStringLiteral":return{type:"terminal",value:e.value};case"AbnfNumVal":return{type:"terminal",value:e.value};case"AbnfRuleName":return{type:"nonterminal",name:e.name};case"AbnfGroup":return i(e.element);case"AbnfOptionalGroup":return{type:"optional",element:i(e.element)};default:throw new Error(`Unsupported ABNF primary node: ${e.$type}`)}},"transformPrimary"),P=n(e=>({name:e.name,definition:i(e.definition)}),"transformRule"),h=n(e=>{f(e,a),e.title&&a.setTitle(e.title),e.rules.map(r=>a.addRule(P(r)))},"populateDb"),R={parse:n(e=>{a.clear(),o.debug("[ABNF Parser] Starting Langium parse");const r=v.parse(e);if(r.lexerErrors.length>0||r.parserErrors.length>0)throw new c(r);const t=r.value;o.debug("[ABNF Parser] Parsed rules:",t.rules.length),h(t),o.debug("[ABNF Parser] Parse complete")},"parse"),parser:{yy:a}},B={parser:R,db:a,renderer:u,styles:p};export{B as diagram};
@@ -1 +1 @@
1
- import{Y as ln,$ as an,a0 as F,a1 as q,a2 as j,a3 as un,a4 as y,a5 as tn,a6 as J,a7 as _,a8 as rn,a9 as o,aa as on,ab as sn,ac as fn}from"./mermaid.core-DpiXCPQI.js";function cn(l){return l.innerRadius}function yn(l){return l.outerRadius}function gn(l){return l.startAngle}function dn(l){return l.endAngle}function mn(l){return l&&l.padAngle}function pn(l,h,I,D,v,A,z,a){var O=I-l,i=D-h,n=z-v,d=a-A,u=d*O-n*i;if(!(u*u<y))return u=(n*(h-A)-d*(l-v))/u,[l+u*O,h+u*i]}function U(l,h,I,D,v,A,z){var a=l-I,O=h-D,i=(z?A:-A)/J(a*a+O*O),n=i*O,d=-i*a,u=l+n,s=h+d,f=I+n,c=D+d,B=(u+f)/2,t=(s+c)/2,m=f-u,g=c-s,R=m*m+g*g,T=v-A,P=u*c-f*s,S=(g<0?-1:1)*J(on(0,T*T*R-P*P)),Y=(P*g-m*S)/R,$=(-P*m-g*S)/R,w=(P*g+m*S)/R,p=(-P*m+g*S)/R,x=Y-B,e=$-t,r=w-B,C=p-t;return x*x+e*e>r*r+C*C&&(Y=w,$=p),{cx:Y,cy:$,x01:-n,y01:-d,x11:Y*(v/T-1),y11:$*(v/T-1)}}function hn(){var l=cn,h=yn,I=j(0),D=null,v=gn,A=dn,z=mn,a=null,O=ln(i);function i(){var n,d,u=+l.apply(this,arguments),s=+h.apply(this,arguments),f=v.apply(this,arguments)-un,c=A.apply(this,arguments)-un,B=rn(c-f),t=c>f;if(a||(a=n=O()),s<u&&(d=s,s=u,u=d),!(s>y))a.moveTo(0,0);else if(B>tn-y)a.moveTo(s*F(f),s*q(f)),a.arc(0,0,s,f,c,!t),u>y&&(a.moveTo(u*F(c),u*q(c)),a.arc(0,0,u,c,f,t));else{var m=f,g=c,R=f,T=c,P=B,S=B,Y=z.apply(this,arguments)/2,$=Y>y&&(D?+D.apply(this,arguments):J(u*u+s*s)),w=_(rn(s-u)/2,+I.apply(this,arguments)),p=w,x=w,e,r;if($>y){var C=sn($/u*q(Y)),K=sn($/s*q(Y));(P-=C*2)>y?(C*=t?1:-1,R+=C,T-=C):(P=0,R=T=(f+c)/2),(S-=K*2)>y?(K*=t?1:-1,m+=K,g-=K):(S=0,m=g=(f+c)/2)}var G=s*F(m),H=s*q(m),L=u*F(T),M=u*q(T);if(w>y){var N=s*F(g),Q=s*q(g),V=u*F(R),W=u*q(R),E;if(B<an)if(E=pn(G,H,V,W,N,Q,L,M)){var X=G-E[0],Z=H-E[1],b=N-E[0],k=Q-E[1],nn=1/q(fn((X*b+Z*k)/(J(X*X+Z*Z)*J(b*b+k*k)))/2),en=J(E[0]*E[0]+E[1]*E[1]);p=_(w,(u-en)/(nn-1)),x=_(w,(s-en)/(nn+1))}else p=x=0}S>y?x>y?(e=U(V,W,G,H,s,x,t),r=U(N,Q,L,M,s,x,t),a.moveTo(e.cx+e.x01,e.cy+e.y01),x<w?a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,s,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),!t),a.arc(r.cx,r.cy,x,o(r.y11,r.x11),o(r.y01,r.x01),!t))):(a.moveTo(G,H),a.arc(0,0,s,m,g,!t)):a.moveTo(G,H),!(u>y)||!(P>y)?a.lineTo(L,M):p>y?(e=U(L,M,N,Q,u,-p,t),r=U(G,H,V,W,u,-p,t),a.lineTo(e.cx+e.x01,e.cy+e.y01),p<w?a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,u,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),t),a.arc(r.cx,r.cy,p,o(r.y11,r.x11),o(r.y01,r.x01),!t))):a.arc(0,0,u,T,R,t)}if(a.closePath(),n)return a=null,n+""||null}return i.centroid=function(){var n=(+l.apply(this,arguments)+ +h.apply(this,arguments))/2,d=(+v.apply(this,arguments)+ +A.apply(this,arguments))/2-an/2;return[F(d)*n,q(d)*n]},i.innerRadius=function(n){return arguments.length?(l=typeof n=="function"?n:j(+n),i):l},i.outerRadius=function(n){return arguments.length?(h=typeof n=="function"?n:j(+n),i):h},i.cornerRadius=function(n){return arguments.length?(I=typeof n=="function"?n:j(+n),i):I},i.padRadius=function(n){return arguments.length?(D=n==null?null:typeof n=="function"?n:j(+n),i):D},i.startAngle=function(n){return arguments.length?(v=typeof n=="function"?n:j(+n),i):v},i.endAngle=function(n){return arguments.length?(A=typeof n=="function"?n:j(+n),i):A},i.padAngle=function(n){return arguments.length?(z=typeof n=="function"?n:j(+n),i):z},i.context=function(n){return arguments.length?(a=n??null,i):a},i}export{hn as d};
1
+ import{Y as ln,$ as an,a0 as F,a1 as q,a2 as j,a3 as un,a4 as y,a5 as tn,a6 as J,a7 as _,a8 as rn,a9 as o,aa as on,ab as sn,ac as fn}from"./mermaid.core-BjB4Bulu.js";function cn(l){return l.innerRadius}function yn(l){return l.outerRadius}function gn(l){return l.startAngle}function dn(l){return l.endAngle}function mn(l){return l&&l.padAngle}function pn(l,h,I,D,v,A,z,a){var O=I-l,i=D-h,n=z-v,d=a-A,u=d*O-n*i;if(!(u*u<y))return u=(n*(h-A)-d*(l-v))/u,[l+u*O,h+u*i]}function U(l,h,I,D,v,A,z){var a=l-I,O=h-D,i=(z?A:-A)/J(a*a+O*O),n=i*O,d=-i*a,u=l+n,s=h+d,f=I+n,c=D+d,B=(u+f)/2,t=(s+c)/2,m=f-u,g=c-s,R=m*m+g*g,T=v-A,P=u*c-f*s,S=(g<0?-1:1)*J(on(0,T*T*R-P*P)),Y=(P*g-m*S)/R,$=(-P*m-g*S)/R,w=(P*g+m*S)/R,p=(-P*m+g*S)/R,x=Y-B,e=$-t,r=w-B,C=p-t;return x*x+e*e>r*r+C*C&&(Y=w,$=p),{cx:Y,cy:$,x01:-n,y01:-d,x11:Y*(v/T-1),y11:$*(v/T-1)}}function hn(){var l=cn,h=yn,I=j(0),D=null,v=gn,A=dn,z=mn,a=null,O=ln(i);function i(){var n,d,u=+l.apply(this,arguments),s=+h.apply(this,arguments),f=v.apply(this,arguments)-un,c=A.apply(this,arguments)-un,B=rn(c-f),t=c>f;if(a||(a=n=O()),s<u&&(d=s,s=u,u=d),!(s>y))a.moveTo(0,0);else if(B>tn-y)a.moveTo(s*F(f),s*q(f)),a.arc(0,0,s,f,c,!t),u>y&&(a.moveTo(u*F(c),u*q(c)),a.arc(0,0,u,c,f,t));else{var m=f,g=c,R=f,T=c,P=B,S=B,Y=z.apply(this,arguments)/2,$=Y>y&&(D?+D.apply(this,arguments):J(u*u+s*s)),w=_(rn(s-u)/2,+I.apply(this,arguments)),p=w,x=w,e,r;if($>y){var C=sn($/u*q(Y)),K=sn($/s*q(Y));(P-=C*2)>y?(C*=t?1:-1,R+=C,T-=C):(P=0,R=T=(f+c)/2),(S-=K*2)>y?(K*=t?1:-1,m+=K,g-=K):(S=0,m=g=(f+c)/2)}var G=s*F(m),H=s*q(m),L=u*F(T),M=u*q(T);if(w>y){var N=s*F(g),Q=s*q(g),V=u*F(R),W=u*q(R),E;if(B<an)if(E=pn(G,H,V,W,N,Q,L,M)){var X=G-E[0],Z=H-E[1],b=N-E[0],k=Q-E[1],nn=1/q(fn((X*b+Z*k)/(J(X*X+Z*Z)*J(b*b+k*k)))/2),en=J(E[0]*E[0]+E[1]*E[1]);p=_(w,(u-en)/(nn-1)),x=_(w,(s-en)/(nn+1))}else p=x=0}S>y?x>y?(e=U(V,W,G,H,s,x,t),r=U(N,Q,L,M,s,x,t),a.moveTo(e.cx+e.x01,e.cy+e.y01),x<w?a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,s,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),!t),a.arc(r.cx,r.cy,x,o(r.y11,r.x11),o(r.y01,r.x01),!t))):(a.moveTo(G,H),a.arc(0,0,s,m,g,!t)):a.moveTo(G,H),!(u>y)||!(P>y)?a.lineTo(L,M):p>y?(e=U(L,M,N,Q,u,-p,t),r=U(G,H,V,W,u,-p,t),a.lineTo(e.cx+e.x01,e.cy+e.y01),p<w?a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,u,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),t),a.arc(r.cx,r.cy,p,o(r.y11,r.x11),o(r.y01,r.x01),!t))):a.arc(0,0,u,T,R,t)}if(a.closePath(),n)return a=null,n+""||null}return i.centroid=function(){var n=(+l.apply(this,arguments)+ +h.apply(this,arguments))/2,d=(+v.apply(this,arguments)+ +A.apply(this,arguments))/2-an/2;return[F(d)*n,q(d)*n]},i.innerRadius=function(n){return arguments.length?(l=typeof n=="function"?n:j(+n),i):l},i.outerRadius=function(n){return arguments.length?(h=typeof n=="function"?n:j(+n),i):h},i.cornerRadius=function(n){return arguments.length?(I=typeof n=="function"?n:j(+n),i):I},i.padRadius=function(n){return arguments.length?(D=n==null?null:typeof n=="function"?n:j(+n),i):D},i.startAngle=function(n){return arguments.length?(v=typeof n=="function"?n:j(+n),i):v},i.endAngle=function(n){return arguments.length?(A=typeof n=="function"?n:j(+n),i):A},i.padAngle=function(n){return arguments.length?(z=typeof n=="function"?n:j(+n),i):z},i.context=function(n){return arguments.length?(a=n??null,i):a},i}export{hn as d};