@tea-agent/loop-agent 0.39.0-next.26 → 0.39.0-next.28

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 (115) hide show
  1. package/AGENTS.md +3 -0
  2. package/CHANGELOG.md +148 -96
  3. package/README.md +8 -4
  4. package/bin/loop-agent.js +7 -3
  5. package/dist/build-stamp.json +3 -3
  6. package/dist/cli/command-definitions.js +16 -5
  7. package/dist/cli/program.js +16 -2
  8. package/dist/cli/update/notifier.js +2 -2
  9. package/dist/cli.js +2 -1
  10. package/dist/commands/init-model-catalog.js +464 -0
  11. package/dist/commands/init-upgrade.js +265 -97
  12. package/dist/commands/init.js +428 -27
  13. package/dist/commands/inspect-next.js +8 -0
  14. package/dist/executors/dag-pi-executor.js +76 -10
  15. package/dist/executors/pi-extension-resolver.js +233 -0
  16. package/dist/executors/pi-sdk-executor.js +79 -2
  17. package/dist/executors/shell-executor.js +50 -6
  18. package/dist/executors/shell-write-guard.js +7 -0
  19. package/dist/shared/operator/capabilities.js +7 -0
  20. package/dist/shared/update/console-notifier.js +100 -0
  21. package/dist/{cli → shared}/update/npm-client.js +41 -8
  22. package/dist/{cli → shared}/update/state.js +41 -13
  23. package/dist/worker/cli.js +31 -1
  24. package/dist/worker/console/chat/routes.js +1 -0
  25. package/dist/worker/console/operator-user-error.js +1 -1
  26. package/dist/worker/console/routes.js +3 -0
  27. package/dist/worker/console/security.js +53 -5
  28. package/dist/worker/console/server.js +10 -4
  29. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-C4kVYweA.js → abnfDiagram-N423BO3Z-DGn9iNrd.js} +1 -1
  30. package/dist/worker/console/static/assets/{arc-Bj2M8iO5.js → arc-Dc0C2Nyv.js} +1 -1
  31. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-CLlXe4-6.js → architectureDiagram-T3A2C74G-COnz_Bhe.js} +1 -1
  32. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-psEp5xH0.js → blockDiagram-VBNYF7ZC-VhIP6vgf.js} +1 -1
  33. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-DeKcOCGJ.js → c4Diagram-5PPSVZJV-D74lpmlb.js} +1 -1
  34. package/dist/worker/console/static/assets/channel-DWcZjWB3.js +1 -0
  35. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-K0C744p1.js → chunk-2GRJ4B5K-BxmiogQE.js} +1 -1
  36. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-xbNw4J9-.js → chunk-2Q5K7J3B-C00Oi-2I.js} +1 -1
  37. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-DjLaSDUO.js → chunk-5RXB4S5H-DTrT1Vze.js} +1 -1
  38. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-CtiPlKel.js → chunk-5VM5RSS4-DdKW7-fL.js} +1 -1
  39. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DZtolir7.js → chunk-6Q2QTUOP-D0q1WN6w.js} +1 -1
  40. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-CPcdNeew.js → chunk-GF5L2VYU-DBa14MSI.js} +1 -1
  41. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-NgHc6V37.js → chunk-JWPE2WC7-DkP-pEox.js} +1 -1
  42. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-DQ_T-hg8.js → chunk-KBJHAD2P-lgPogpcX.js} +1 -1
  43. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-DgLsxcVP.js → chunk-RYQCIY6F-D-apZer0.js} +1 -1
  44. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-UrVoM9z1.js → chunk-XXDRQBXY-B1T2yAIe.js} +1 -1
  45. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-IjoI3dqU.js +1 -0
  46. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-IjoI3dqU.js +1 -0
  47. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-CLkYvTb3.js → cose-bilkent-JH36ORCC-0P6hi3jF.js} +1 -1
  48. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-BwT_xKrE.js → cynefin-VYW2F7L2-CntzMSR8.js} +1 -1
  49. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-Bi9tuzif.js → cynefinDiagram-MW4NZA55-C9zmXJtG.js} +1 -1
  50. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-BCIqkWBV.js → dagre-VZM6K2ZE-DfBCZqZw.js} +1 -1
  51. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-Dip6l9_Z.js → diagram-7IWD3JNH-DLp-bhGL.js} +1 -1
  52. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-B-xkh_wK.js → diagram-B4RE2ZJO-BksDcwZm.js} +1 -1
  53. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-DZO0kTt_.js → diagram-LBJQPF4R-Bdag7DYP.js} +1 -1
  54. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-D6ZplNbZ.js → diagram-Q27KOJAE-CoY5uNbk.js} +1 -1
  55. package/dist/worker/console/static/assets/{diagram-UB23O5K3-BPekbhoS.js → diagram-UB23O5K3-KcgrDXHt.js} +1 -1
  56. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-BtmaJpK5.js → ebnfDiagram-BXEA7PRR-CikErwJb.js} +1 -1
  57. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-6DS0Xc44.js → erDiagram-JOGREHBK-DqmwwzvZ.js} +1 -1
  58. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-CihnROSm.js → flowDiagram-UKHOOZJN-35krh9WG.js} +1 -1
  59. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-CZC4zOE2.js → ganttDiagram-PKOTCBZU-CvTF1gJ4.js} +1 -1
  60. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-Dq1fhzGN.js → gitGraphDiagram-DS77QQ5N-BiOWWClJ.js} +1 -1
  61. package/dist/worker/console/static/assets/{index-DTZOKgAn.js → index-CqWlWE4l.js} +3 -3
  62. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-DlSl4BGx.js → infoDiagram-6WML65LV-Crha5dcA.js} +1 -1
  63. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-snnzFl_U.js → ishikawaDiagram-WSZJBQD7-DEtbscOZ.js} +1 -1
  64. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-BDE7qpMx.js → journeyDiagram-NVQOT4AX-D2YYzx3z.js} +1 -1
  65. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-CD2Ci04G.js → kanban-definition-27J2QSJJ-C7x18ttQ.js} +1 -1
  66. package/dist/worker/console/static/assets/{linear-DdnapKIH.js → linear-CCLZkz45.js} +1 -1
  67. package/dist/worker/console/static/assets/{mermaid.core-BVjAT9b8.js → mermaid.core-Dmy4lSGv.js} +5 -5
  68. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-D0yJk-zA.js → mindmap-definition-FAOFIHXS-CmvIol59.js} +1 -1
  69. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-BVo9tFP-.js → pegDiagram-VL7TDLO6-DVpEdirN.js} +1 -1
  70. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-DnOV-mZ_.js → pieDiagram-7S7Q4E2Y-cKQy456v.js} +1 -1
  71. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-CzUJo58i.js → quadrantDiagram-CIZ2JOQS-bx06I38m.js} +1 -1
  72. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-Bvikrolh.js → railroadDiagram-AXF67PYL-BjfIVIJr.js} +1 -1
  73. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-DtaSVCap.js → requirementDiagram-LRYGKXZP-DcuPGbKM.js} +1 -1
  74. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-C2c9A0wW.js → sankeyDiagram-W5VNT64P-DvgVeDoV.js} +1 -1
  75. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-DmXJcU7r.js → sequenceDiagram-SI44F4Z6-DLBG9nm-.js} +1 -1
  76. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-B4GUFW92.js → sizeCapture-X5ZJPWSS-D33L7FBF.js} +1 -1
  77. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-Dsad2MXf.js → stateDiagram-OKZ733FA-hvqD9TpS.js} +1 -1
  78. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-C6MII0D1.js +1 -0
  79. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-DGq48Fbi.js → swimlanes-SLNWSIFB-BtjH81Mz.js} +2 -2
  80. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-D_tk0V8D.js +8 -0
  81. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-CSSi6OFf.js → timeline-definition-Z64GVDOM-CJ47Kraf.js} +1 -1
  82. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-BqyzPrWv.js → vennDiagram-T6HMQDX7-COVPl-wh.js} +1 -1
  83. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-DlznVb6S.js → wardleyDiagram-T6FBY63Y-CCoQJLUY.js} +1 -1
  84. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-CfBcgJ_K.js → xychartDiagram-ELKLHX3M-DTWJvfAd.js} +1 -1
  85. package/dist/worker/console/static/index.html +1 -1
  86. package/dist/worker/console/static-src/operator-chat/mutation-gate.js +1 -1
  87. package/dist/worker/observe/node-input.js +72 -3
  88. package/dist/worker/observe/static/dag-history-labels.js +4 -0
  89. package/dist/worker/observe/static/views/dag-inspector.js +54 -1
  90. package/dist/worker/observe/static/views/session-timeline.js +60 -4
  91. package/dist/workflows/dag/contract-output-registry.js +15 -0
  92. package/dist/workflows/dag/failure-category.js +5 -0
  93. package/dist/workflows/dag/frontend-implementation-contract.js +145 -40
  94. package/dist/workflows/dag/frontend-prewrite-gate.js +87 -135
  95. package/dist/workflows/dag/init-hybrid.js +71 -80
  96. package/dist/workflows/dag/node-execution.js +139 -10
  97. package/dist/workflows/dag/prompt.js +15 -1
  98. package/dist/workflows/dag/retry-policy.js +91 -0
  99. package/dist/workflows/dag/structured-output-repair.js +712 -0
  100. package/dist/workflows/dag/types.js +28 -1
  101. package/dist/workflows/dag/validate.js +39 -1
  102. package/docs/init-surface.manifest.json +5 -0
  103. package/docs/operations/README.md +1 -1
  104. package/docs/templates/agent-dag.schema.json +13 -0
  105. package/docs/templates/init-managed-agents.md +13 -3
  106. package/package.json +5 -1
  107. package/scripts/next-info.mjs +356 -0
  108. package/scripts/next-publish-gate.mjs +238 -0
  109. package/scripts/release-source-binding.mjs +251 -0
  110. package/skills/loop-agent/references/command-reference.md +11 -4
  111. package/dist/worker/console/static/assets/channel-CPF4N7pf.js +0 -1
  112. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-C2DwA_Y1.js +0 -1
  113. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-C2DwA_Y1.js +0 -1
  114. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-B8FB_cNk.js +0 -1
  115. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-CrZYaWfx.js +0 -8
@@ -0,0 +1,100 @@
1
+ import { createInterface } from "node:readline/promises";
2
+ import semver from "semver";
3
+ import { acquireUpdateLock, readUpdateState, updateLockPath, updateStatePath, writeUpdateState, } from "./state.js";
4
+ export async function runConsoleDailyUpdateCheck(options) {
5
+ void options.writeStdout;
6
+ void options.packageRoot;
7
+ void options.cwd;
8
+ const writeStderr = options.writeStderr ?? ((chunk) => process.stderr.write(chunk));
9
+ const now = options.now ?? (() => new Date());
10
+ try {
11
+ if (!canPromptInteractively(options))
12
+ return;
13
+ const statePath = updateStatePath(options.homeDir);
14
+ const today = formatLocalDate(now());
15
+ const existing = await readUpdateState(statePath);
16
+ if (existing.lastPromptedLocalDate === today)
17
+ return;
18
+ const release = await acquireUpdateLock(updateLockPath(options.homeDir), {
19
+ now,
20
+ });
21
+ if (!release)
22
+ return;
23
+ try {
24
+ const state = await readUpdateState(statePath);
25
+ if (state.lastPromptedLocalDate === today)
26
+ return;
27
+ const check = await options.client.latestVersionCheck();
28
+ if (!check.ok)
29
+ return;
30
+ if (!semver.gt(check.version, options.currentVersion))
31
+ return;
32
+ const parsedLatest = semver.parse(check.version);
33
+ if (!parsedLatest || parsedLatest.prerelease.length > 0)
34
+ return;
35
+ await markPromptedToday(statePath, state, today);
36
+ const answer = await ask(options, `loop-agent 有新版本:${options.currentVersion} → ${check.version}\n现在更新到 ${check.version}?[y/N] `);
37
+ if (!isYes(answer))
38
+ return;
39
+ const proof = await options.client.canAutoInstall();
40
+ if (!proof.ok) {
41
+ writeStderr(`当前 loop-agent 不是由此 npm 的正式全局安装管理,无法自动升级。\n请运行:npm install -g @tea-agent/loop-agent@${check.version}\n`);
42
+ return;
43
+ }
44
+ const install = await options.client.installExact(check.version);
45
+ if (!install.ok) {
46
+ writeStderr(`loop-agent 更新失败:${install.reason}\n`);
47
+ return;
48
+ }
49
+ const verified = await options.client.verifyInstalled(check.version);
50
+ if (!verified.ok) {
51
+ writeStderr(`loop-agent 已尝试安装,但验证失败:${verified.reason}\n`);
52
+ return;
53
+ }
54
+ writeStderr(`loop-agent 已更新到 ${check.version};新版本将在下一次命令调用时完全生效。\n`);
55
+ }
56
+ finally {
57
+ await release().catch(() => undefined);
58
+ }
59
+ }
60
+ catch (error) {
61
+ writeStderr(`loop-agent 更新检查已跳过:${error instanceof Error ? error.message : String(error)}\n`);
62
+ }
63
+ }
64
+ function canPromptInteractively(options) {
65
+ if (!options.stdinIsTTY || !options.stderrIsTTY)
66
+ return false;
67
+ if (options.env.CI)
68
+ return false;
69
+ if (options.env.LOOP_AGENT_DISABLE_UPDATE_CHECK === "1")
70
+ return false;
71
+ return true;
72
+ }
73
+ function formatLocalDate(date) {
74
+ const year = date.getFullYear();
75
+ const month = String(date.getMonth() + 1).padStart(2, "0");
76
+ const day = String(date.getDate()).padStart(2, "0");
77
+ return `${year}-${month}-${day}`;
78
+ }
79
+ async function markPromptedToday(statePath, state, today) {
80
+ await writeUpdateState(statePath, {
81
+ ...state,
82
+ lastPromptedLocalDate: today,
83
+ });
84
+ }
85
+ async function ask(options, prompt) {
86
+ if (options.readLine) {
87
+ options.writeStderr?.(prompt);
88
+ return options.readLine(prompt);
89
+ }
90
+ const rl = createInterface({ input: process.stdin, output: process.stderr });
91
+ try {
92
+ return await rl.question(prompt);
93
+ }
94
+ finally {
95
+ rl.close();
96
+ }
97
+ }
98
+ function isYes(answer) {
99
+ return /^(y|yes)$/i.test(answer.trim());
100
+ }
@@ -3,25 +3,48 @@ import { lstat, readFile, realpath } from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  import semver from "semver";
5
5
  const PACKAGE_NAME = "@tea-agent/loop-agent";
6
+ export const DEFAULT_NPM_QUERY_TIMEOUT_MS = 15_000;
6
7
  export function createNpmUpdateClient(options) {
7
8
  const npmCommand = options.npmCommand ?? "npm";
8
9
  const loopAgentCommand = options.loopAgentCommand ?? "loop-agent";
9
10
  const runner = options.runner ?? runCommand;
10
- const timeoutMs = options.timeoutMs ?? 1500;
11
+ const timeoutMs = options.timeoutMs ?? DEFAULT_NPM_QUERY_TIMEOUT_MS;
12
+ const cwd = options.cwd;
11
13
  const env = options.env;
14
+ const latestVersionCheck = async () => {
15
+ let result;
16
+ try {
17
+ result = await runner(npmCommand, ["view", PACKAGE_NAME, "dist-tags.latest", "--json"], { timeoutMs, cwd, env });
18
+ }
19
+ catch {
20
+ return { ok: false, reason: "spawn-failure" };
21
+ }
22
+ if (result.timedOut)
23
+ return { ok: false, reason: "timeout" };
24
+ if (result.exitCode === null) {
25
+ return { ok: false, reason: "spawn-failure" };
26
+ }
27
+ if (result.exitCode !== 0) {
28
+ return { ok: false, reason: "command-failed" };
29
+ }
30
+ const version = parseNpmViewLatest(result.stdout);
31
+ return version
32
+ ? { ok: true, version }
33
+ : { ok: false, reason: "invalid-response" };
34
+ };
12
35
  return {
13
36
  async latestVersion() {
14
- const result = await runner(npmCommand, ["view", PACKAGE_NAME, "dist-tags.latest", "--json"], { timeoutMs, env });
15
- if (result.exitCode !== 0 || result.timedOut)
16
- return undefined;
17
- return parseNpmViewLatest(result.stdout);
37
+ const result = await latestVersionCheck();
38
+ return result.ok ? result.version : undefined;
18
39
  },
40
+ latestVersionCheck,
19
41
  async canAutoInstall() {
20
42
  return proveGlobalNpmInstall({
21
43
  currentVersion: options.currentVersion,
22
44
  packageRoot: options.packageRoot,
23
45
  npmCommand,
24
46
  runner,
47
+ cwd,
25
48
  env,
26
49
  timeoutMs,
27
50
  });
@@ -29,17 +52,25 @@ export function createNpmUpdateClient(options) {
29
52
  async installExact(version) {
30
53
  if (!isStrictRelease(version))
31
54
  return { ok: false, reason: "invalid-version" };
32
- const result = await runner(npmCommand, buildExactInstallArgs(version), { timeoutMs: Math.max(timeoutMs, 120000), env });
55
+ const result = await runner(npmCommand, buildExactInstallArgs(version), {
56
+ timeoutMs: Math.max(timeoutMs, 120000),
57
+ cwd,
58
+ env,
59
+ });
33
60
  if (result.exitCode !== 0 || result.timedOut)
34
61
  return { ok: false, reason: "install-failed" };
35
62
  return { ok: true };
36
63
  },
37
64
  async verifyInstalled(version) {
38
- const list = await runner(npmCommand, ["list", "-g", PACKAGE_NAME, "--depth=0", "--json"], { timeoutMs, env });
65
+ const list = await runner(npmCommand, ["list", "-g", PACKAGE_NAME, "--depth=0", "--json"], { timeoutMs, cwd, env });
39
66
  if (list.exitCode !== 0 || !verifyNpmListVersion(list.stdout, version)) {
40
67
  return { ok: false, reason: "npm-list-version-mismatch" };
41
68
  }
42
- const pathVersion = await runner(loopAgentCommand, ["--version"], { timeoutMs, env });
69
+ const pathVersion = await runner(loopAgentCommand, ["--version"], {
70
+ timeoutMs,
71
+ cwd,
72
+ env,
73
+ });
43
74
  if (pathVersion.exitCode !== 0 || !verifyPathVersion(pathVersion.stdout, version)) {
44
75
  return { ok: false, reason: "path-version-mismatch" };
45
76
  }
@@ -80,6 +111,7 @@ export function verifyPathVersion(stdout, expectedVersion) {
80
111
  async function proveGlobalNpmInstall(options) {
81
112
  const root = await options.runner(options.npmCommand, ["root", "-g"], {
82
113
  timeoutMs: options.timeoutMs,
114
+ cwd: options.cwd,
83
115
  env: options.env,
84
116
  });
85
117
  if (root.exitCode !== 0 || root.timedOut)
@@ -113,6 +145,7 @@ function isStrictRelease(version) {
113
145
  async function runCommand(command, args, options) {
114
146
  return new Promise((resolve) => {
115
147
  const child = spawn(command, [...args], {
148
+ cwd: options.cwd,
116
149
  env: options.env ? { ...process.env, ...options.env } : process.env,
117
150
  stdio: ["ignore", "pipe", "pipe"],
118
151
  shell: false,
@@ -1,4 +1,4 @@
1
- import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
1
+ import { mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  export function updateStatePath(homeDir) {
4
4
  return path.join(homeDir, ".loop-agent", "update-state.json");
@@ -18,6 +18,7 @@ export async function readUpdateState(statePath) {
18
18
  latestVersion: stringOrUndefined(parsed.latestVersion),
19
19
  dismissedVersion: stringOrUndefined(parsed.dismissedVersion),
20
20
  retryAfter: stringOrUndefined(parsed.retryAfter),
21
+ lastPromptedLocalDate: stringOrUndefined(parsed.lastPromptedLocalDate),
21
22
  };
22
23
  }
23
24
  catch {
@@ -36,28 +37,55 @@ export async function acquireUpdateLock(lockPath, options = {}) {
36
37
  await mkdir(path.dirname(lockPath), { recursive: true });
37
38
  try {
38
39
  await mkdir(lockPath);
40
+ return await claimLock(lockPath, now);
41
+ }
42
+ catch {
43
+ if (await isFreshLock(lockPath, now, staleMs))
44
+ return undefined;
45
+ try {
46
+ await rm(lockPath, { recursive: true, force: true });
47
+ await mkdir(lockPath);
48
+ return await claimLock(lockPath, now);
49
+ }
50
+ catch {
51
+ return undefined;
52
+ }
53
+ }
54
+ }
55
+ async function claimLock(lockPath, now) {
56
+ try {
39
57
  await writeFile(path.join(lockPath, "owner.json"), JSON.stringify({ pid: process.pid, at: now().toISOString() }), "utf-8");
40
58
  return async () => {
41
59
  await rm(lockPath, { recursive: true, force: true });
42
60
  };
43
61
  }
62
+ catch {
63
+ await rm(lockPath, { recursive: true, force: true }).catch(() => undefined);
64
+ return undefined;
65
+ }
66
+ }
67
+ async function isFreshLock(lockPath, now, staleMs) {
68
+ try {
69
+ const ownerRaw = await readFile(path.join(lockPath, "owner.json"), "utf-8");
70
+ const owner = JSON.parse(ownerRaw);
71
+ if (typeof owner.at !== "string")
72
+ return false;
73
+ const at = Date.parse(owner.at);
74
+ if (!Number.isFinite(at))
75
+ return false;
76
+ return now().getTime() - at <= staleMs;
77
+ }
44
78
  catch {
45
79
  try {
46
- const ownerRaw = await readFile(path.join(lockPath, "owner.json"), "utf-8");
47
- const owner = JSON.parse(ownerRaw);
48
- if (owner.at && now().getTime() - Date.parse(owner.at) > staleMs) {
49
- await rm(lockPath, { recursive: true, force: true });
50
- await mkdir(lockPath);
51
- await writeFile(path.join(lockPath, "owner.json"), JSON.stringify({ pid: process.pid, at: now().toISOString() }), "utf-8");
52
- return async () => {
53
- await rm(lockPath, { recursive: true, force: true });
54
- };
55
- }
80
+ const info = await stat(lockPath);
81
+ const mtime = Number.isFinite(info.mtimeMs)
82
+ ? info.mtimeMs
83
+ : info.mtime.getTime();
84
+ return now().getTime() - mtime <= staleMs;
56
85
  }
57
86
  catch {
58
- return undefined;
87
+ return false;
59
88
  }
60
- return undefined;
61
89
  }
62
90
  }
63
91
  function emptyState() {
@@ -1,8 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import { readFile } from "node:fs/promises";
3
+ import os from "node:os";
3
4
  import path from "node:path";
4
5
  import { fileURLToPath } from "node:url";
5
6
  import { Command } from "commander";
7
+ import { createNpmUpdateClient } from "../shared/update/npm-client.js";
8
+ import { runConsoleDailyUpdateCheck } from "../shared/update/console-notifier.js";
6
9
  import { readPackageVersion } from "../shared/package-metadata.js";
7
10
  import YAML from "yaml";
8
11
  import { LoopAgentClient } from "./loop-agent/loop-agent-client.js";
@@ -838,10 +841,33 @@ function parseOptionalTimeoutMs(raw) {
838
841
  return value;
839
842
  }
840
843
  /** Console HTTP entry for bare `agent-worker console` (listen first, then optional browser open). */
841
- async function runConsoleServe(options) {
844
+ export async function runConsoleServe(options) {
842
845
  const { createConsoleServer } = await import("./console/server.js");
843
846
  const { maybeOpenConsoleBrowser } = await import("./console/open-browser.js");
844
847
  try {
848
+ try {
849
+ const packageRoot = path.dirname(path.dirname(path.dirname(fileURLToPath(import.meta.url))));
850
+ const currentVersion = readPackageVersion(packageRoot) ?? "0.0.0";
851
+ await runConsoleDailyUpdateCheck({
852
+ currentVersion,
853
+ packageRoot,
854
+ homeDir: os.homedir(),
855
+ cwd: options.repoRoot,
856
+ env: process.env,
857
+ stdinIsTTY: process.stdin.isTTY === true,
858
+ stderrIsTTY: process.stderr.isTTY === true,
859
+ client: createNpmUpdateClient({
860
+ currentVersion,
861
+ packageRoot,
862
+ cwd: options.repoRoot,
863
+ env: process.env,
864
+ }),
865
+ });
866
+ }
867
+ catch (error) {
868
+ const detail = error instanceof Error ? error.message : String(error);
869
+ process.stderr.write(`loop-agent 更新检查已跳过:${detail}\n`);
870
+ }
845
871
  const server = await createConsoleServer({
846
872
  repoRoot: options.repoRoot,
847
873
  host: options.host,
@@ -857,6 +883,10 @@ async function runConsoleServe(options) {
857
883
  noOpen: options.noOpen === true,
858
884
  serverUrl: server.url,
859
885
  });
886
+ if (options.holdUntilSignal === false) {
887
+ await server.close();
888
+ return;
889
+ }
860
890
  await new Promise((resolve) => {
861
891
  const shutdown = () => resolve();
862
892
  process.once("SIGINT", shutdown);
@@ -270,6 +270,7 @@ export function parseChatImages(value) {
270
270
  }
271
271
  function gateMutation(req, deps) {
272
272
  const failure = evaluateMutationGate(req, {
273
+ cookieName: deps.bootToken.cookieName,
273
274
  bootToken: deps.bootToken.value,
274
275
  confirmationToken: deps.bootToken.confirmationToken,
275
276
  consoleOrigin: deps.getConsoleOrigin(),
@@ -3,7 +3,7 @@ import { rewriteRecoveryOperatorError } from "./recovery-error-copy.js";
3
3
  const MUTATION_GATE_COPY = [
4
4
  {
5
5
  pattern: /invalid (boot capability|confirmation header) token/i,
6
- copy: "页面已过期(控制台已重启),请刷新页面(F5)后重试。",
6
+ copy: "页面凭证已失效(控制台可能已重启),请刷新页面(F5)后重试。",
7
7
  },
8
8
  {
9
9
  pattern: /mutation requires boot capability cookie|mutation requires confirmation header token/i,
@@ -116,6 +116,7 @@ async function handleRecoveryCandidates(_req, res, ctx, url) {
116
116
  }
117
117
  async function handleSessionPing(req, res, ctx) {
118
118
  const failure = evaluateMutationGate(req, {
119
+ cookieName: ctx.bootToken.cookieName,
119
120
  bootToken: ctx.bootToken.value,
120
121
  confirmationToken: ctx.bootToken.confirmationToken,
121
122
  consoleOrigin: ctx.getConsoleOrigin(),
@@ -142,6 +143,7 @@ async function handleCreateOperation(req, res, ctx) {
142
143
  return;
143
144
  }
144
145
  const failure = evaluateMutationGate(req, {
146
+ cookieName: ctx.bootToken.cookieName,
145
147
  bootToken: ctx.bootToken.value,
146
148
  confirmationToken: ctx.bootToken.confirmationToken,
147
149
  consoleOrigin: ctx.getConsoleOrigin(),
@@ -428,6 +430,7 @@ export async function handleConsoleOperatorRequest(req, res, ctx) {
428
430
  }
429
431
  if (isMutationMethod(method)) {
430
432
  const failure = evaluateMutationGate(req, {
433
+ cookieName: ctx.bootToken.cookieName,
431
434
  bootToken: ctx.bootToken.value,
432
435
  confirmationToken: ctx.bootToken.confirmationToken,
433
436
  consoleOrigin: ctx.getConsoleOrigin(),
@@ -1,19 +1,67 @@
1
- import { randomBytes, timingSafeEqual } from "node:crypto";
1
+ import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
2
2
  import { isLoopbackHost } from "./loopback.js";
3
+ /** Prefix for instance-scoped Cookie names; not a lookup name. */
3
4
  export const BOOT_CAPABILITY_COOKIE = "loop_console_capability";
4
5
  /** Custom mutation confirmation header (design §9). JS-readable; not the HttpOnly boot cookie. */
5
6
  export const CONFIRMATION_TOKEN_HEADER = "x-loop-console-confirmation";
7
+ function normalizeInstanceScope(scope) {
8
+ const repoFingerprint = scope.repoFingerprint.trim();
9
+ if (!repoFingerprint) {
10
+ throw new Error("console instance scope requires a non-empty repoFingerprint");
11
+ }
12
+ const bindHost = scope.bindHost.trim();
13
+ if (!bindHost) {
14
+ throw new Error("console instance scope requires a non-empty bindHost");
15
+ }
16
+ if (!Number.isInteger(scope.configuredPort) || scope.configuredPort < 0) {
17
+ throw new Error(`console instance scope configuredPort must be an integer >= 0, got ${String(scope.configuredPort)}`);
18
+ }
19
+ const instanceNonce = scope.instanceNonce?.trim();
20
+ if (scope.configuredPort === 0) {
21
+ if (!instanceNonce) {
22
+ throw new Error("console instance scope requires a non-empty instanceNonce when configuredPort is 0");
23
+ }
24
+ return {
25
+ repoFingerprint,
26
+ bindHost,
27
+ configuredPort: 0,
28
+ instanceNonce,
29
+ };
30
+ }
31
+ return {
32
+ repoFingerprint,
33
+ bindHost,
34
+ configuredPort: scope.configuredPort,
35
+ };
36
+ }
37
+ /** Deterministic Cookie name for one Console instance; never includes repo path or token. */
38
+ export function deriveBootCapabilityCookieName(scope) {
39
+ const normalized = normalizeInstanceScope(scope);
40
+ const digest = createHash("sha256")
41
+ .update("loop-console-capability-v1\0", "utf8")
42
+ .update(normalized.repoFingerprint, "utf8")
43
+ .update("\0", "utf8")
44
+ .update(normalized.bindHost, "utf8")
45
+ .update("\0", "utf8")
46
+ .update(String(normalized.configuredPort), "utf8")
47
+ .update("\0", "utf8")
48
+ .update(normalized.instanceNonce ?? "", "utf8")
49
+ .digest("hex")
50
+ .slice(0, 32);
51
+ return `${BOOT_CAPABILITY_COOKIE}_${digest}`;
52
+ }
6
53
  /** Issue per-process unguessable boot capability + confirmation tokens. */
7
- export function issueBootCapabilityToken() {
54
+ export function issueBootCapabilityToken(scope) {
55
+ const cookieName = deriveBootCapabilityCookieName(scope);
8
56
  const value = randomBytes(32).toString("base64url");
9
57
  const confirmationToken = randomBytes(32).toString("base64url");
10
58
  const setCookieHeader = [
11
- `${BOOT_CAPABILITY_COOKIE}=${value}`,
59
+ `${cookieName}=${value}`,
12
60
  "HttpOnly",
13
61
  "SameSite=Strict",
14
62
  "Path=/",
15
63
  ].join("; ");
16
- return { value, setCookieHeader, confirmationToken };
64
+ return { cookieName, value, setCookieHeader, confirmationToken };
17
65
  }
18
66
  /** Inject confirmation token into HTML so the SPA can send the mutation header. */
19
67
  export function injectConfirmationTokenScript(html, confirmationToken) {
@@ -74,7 +122,7 @@ function loopbackOriginMatches(origin, consoleOrigin) {
74
122
  return originKey !== null && consoleKey !== null && originKey === consoleKey;
75
123
  }
76
124
  export function evaluateMutationGate(req, ctx) {
77
- const cookieToken = parseCookieHeader(req.headers.cookie, BOOT_CAPABILITY_COOKIE);
125
+ const cookieToken = parseCookieHeader(req.headers.cookie, ctx.cookieName);
78
126
  if (!cookieToken) {
79
127
  return {
80
128
  status: 403,
@@ -66,7 +66,7 @@ export async function createConsoleServer(options) {
66
66
  process.stderr.write(`console: binding non-loopback host ${host} (Operator mutations enabled; no network auth — expose only on trusted networks)\n`);
67
67
  }
68
68
  const repoRoot = path.resolve(options.repoRoot);
69
- const port = options.port ?? 8790;
69
+ const configuredPort = options.port ?? 8790;
70
70
  const debug = options.debug === true;
71
71
  const keepAliveTimeoutMs = options.keepAliveTimeoutMs ?? 65_000;
72
72
  const staticDir = options.staticDir ?? defaultConsoleStaticDir();
@@ -74,12 +74,18 @@ export async function createConsoleServer(options) {
74
74
  const observeRouteContext = createObserveRouteContext(repoRoot, {
75
75
  staticDir: inspectStaticDir,
76
76
  });
77
- const bootToken = issueBootCapabilityToken();
78
77
  const operatorSessionId = `sess_${randomBytes(16).toString("hex")}`;
79
78
  const appData = openConsoleAppData({
80
79
  repoRoot,
81
80
  appDataRoot: options.appDataRoot,
82
81
  });
82
+ const instanceNonce = configuredPort === 0 ? randomBytes(16).toString("hex") : undefined;
83
+ const bootToken = issueBootCapabilityToken({
84
+ repoFingerprint: appData.fingerprint,
85
+ bindHost: host,
86
+ configuredPort,
87
+ ...(instanceNonce ? { instanceNonce } : {}),
88
+ });
83
89
  const operations = new OperationStore(appData);
84
90
  const events = createOperationEventStore({
85
91
  persistenceDir: path.join(appData.operations, "events"),
@@ -137,7 +143,7 @@ export async function createConsoleServer(options) {
137
143
  getConsoleOrigin: () => `http://${boundHost}:${boundPort}`,
138
144
  };
139
145
  let boundHost = host;
140
- let boundPort = port;
146
+ let boundPort = configuredPort;
141
147
  const getConsoleOrigin = () => `http://${boundHost}:${boundPort}`;
142
148
  // Phase 4: General Operator Chat runtime. The actionContext is forwarded so
143
149
  // custom-tool execute() calls dispatch into the operator action layer (Gate 3).
@@ -289,7 +295,7 @@ export async function createConsoleServer(options) {
289
295
  await serveConsoleStatic(req, res, routeContext);
290
296
  }
291
297
  server.on("error", reject);
292
- server.listen(port, host, () => {
298
+ server.listen(configuredPort, host, () => {
293
299
  const addr = server.address();
294
300
  if (!addr || typeof addr === "string") {
295
301
  reject(new Error("Failed to get console server address"));
@@ -1 +1 @@
1
- import{g as p,r as u,d as a}from"./chunk-6Q2QTUOP-DZtolir7.js";import{p as f}from"./chunk-JWPE2WC7-NgHc6V37.js";import{_ as n,l as o}from"./mermaid.core-BVjAT9b8.js";import{M as c,b as d}from"./cynefin-VYW2F7L2-BwT_xKrE.js";import"./index-DTZOKgAn.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-6Q2QTUOP-D0q1WN6w.js";import{p as f}from"./chunk-JWPE2WC7-DkP-pEox.js";import{_ as n,l as o}from"./mermaid.core-Dmy4lSGv.js";import{M as c,b as d}from"./cynefin-VYW2F7L2-CntzMSR8.js";import"./index-CqWlWE4l.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-BVjAT9b8.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-Dmy4lSGv.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};