a2acalling 0.6.75 → 0.6.76

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 (1025) hide show
  1. package/.a2a-manifest.json +2 -2
  2. package/.claude/worktrees/agent-a0a8dd02/.a2a-manifest.json +70 -0
  3. package/.claude/worktrees/agent-a0a8dd02/.c8rc.json +16 -0
  4. package/.claude/worktrees/agent-a0a8dd02/.claude/a2a-skill-reference.md +462 -0
  5. package/.claude/worktrees/agent-a0a8dd02/.claude/commands/a2a-app.md +42 -0
  6. package/.claude/worktrees/agent-a0a8dd02/.claude/commands/a2a-call.md +26 -0
  7. package/.claude/worktrees/agent-a0a8dd02/.claude/commands/a2a-contacts.md +31 -0
  8. package/.claude/worktrees/agent-a0a8dd02/.claude/commands/a2a-conversations.md +47 -0
  9. package/.claude/worktrees/agent-a0a8dd02/.claude/commands/a2a-gui.md +30 -0
  10. package/.claude/worktrees/agent-a0a8dd02/.claude/commands/a2a-invite.md +63 -0
  11. package/.claude/worktrees/agent-a0a8dd02/.claude/commands/a2a-setup.md +30 -0
  12. package/.claude/worktrees/agent-a0a8dd02/.claude/commands/a2a-skills.md +27 -0
  13. package/.claude/worktrees/agent-a0a8dd02/.claude/commands/a2a-status.md +46 -0
  14. package/.claude/worktrees/agent-a0a8dd02/.claude/commands/a2a-uninstall.md +36 -0
  15. package/.claude/worktrees/agent-a0a8dd02/.claude/commands/a2a-update.md +41 -0
  16. package/.claude/worktrees/agent-a0a8dd02/.node-version +1 -0
  17. package/.claude/worktrees/agent-a0a8dd02/ARCHITECTURE.md +135 -0
  18. package/.claude/worktrees/agent-a0a8dd02/CLAUDE-INSTALL.md +156 -0
  19. package/.claude/worktrees/agent-a0a8dd02/CONVENTIONS.md +179 -0
  20. package/.claude/worktrees/agent-a0a8dd02/README.md +470 -0
  21. package/.claude/worktrees/agent-a0a8dd02/SKILL.md +462 -0
  22. package/.claude/worktrees/agent-a0a8dd02/bin/cli.js +3184 -0
  23. package/.claude/worktrees/agent-a0a8dd02/biome.json +27 -0
  24. package/.claude/worktrees/agent-a0a8dd02/docs/assessments/2026-02-27-google-a2a-protocol-assessment.md +292 -0
  25. package/.claude/worktrees/agent-a0a8dd02/docs/plans/2026-02-15-port-fallback-warning-design.md +611 -0
  26. package/.claude/worktrees/agent-a0a8dd02/docs/plans/2026-02-16-a2a-callbook-macos-app.md +1660 -0
  27. package/.claude/worktrees/agent-a0a8dd02/docs/plans/2026-02-16-auto-updater.md +1284 -0
  28. package/.claude/worktrees/agent-a0a8dd02/docs/plans/2026-02-16-bugfixes-22-24.md +246 -0
  29. package/.claude/worktrees/agent-a0a8dd02/docs/plans/2026-02-16-e2e-test-prompt-sequence.md +3085 -0
  30. package/.claude/worktrees/agent-a0a8dd02/docs/plans/2026-02-16-orphan-process-fix.md +962 -0
  31. package/.claude/worktrees/agent-a0a8dd02/docs/plans/2026-02-17-claude-code-codex-skills.md +770 -0
  32. package/.claude/worktrees/agent-a0a8dd02/docs/plans/2026-03-01-a2a-68-openclaw-integration-tests.md +676 -0
  33. package/.claude/worktrees/agent-a0a8dd02/docs/plans/2026-03-01-a2a-77-invoke-security-tests.md +661 -0
  34. package/.claude/worktrees/agent-a0a8dd02/docs/prompts/e2e-test-agent.md +368 -0
  35. package/.claude/worktrees/agent-a0a8dd02/docs/protocol.md +440 -0
  36. package/.claude/worktrees/agent-a0a8dd02/docs/signing-setup.md +49 -0
  37. package/.claude/worktrees/agent-a0a8dd02/eslint.config.js +16 -0
  38. package/.claude/worktrees/agent-a0a8dd02/knip.json +17 -0
  39. package/.claude/worktrees/agent-a0a8dd02/native/macos/index.html +179 -0
  40. package/.claude/worktrees/agent-a0a8dd02/native/macos/package.json +8 -0
  41. package/.claude/worktrees/agent-a0a8dd02/native/macos/src-tauri/Cargo.lock +5875 -0
  42. package/.claude/worktrees/agent-a0a8dd02/native/macos/src-tauri/Cargo.toml +25 -0
  43. package/.claude/worktrees/agent-a0a8dd02/native/macos/src-tauri/binaries/.gitkeep +0 -0
  44. package/.claude/worktrees/agent-a0a8dd02/native/macos/src-tauri/build.rs +3 -0
  45. package/.claude/worktrees/agent-a0a8dd02/native/macos/src-tauri/capabilities/default.json +26 -0
  46. package/.claude/worktrees/agent-a0a8dd02/native/macos/src-tauri/entitlements.plist +14 -0
  47. package/.claude/worktrees/agent-a0a8dd02/native/macos/src-tauri/icons/128x128.png +0 -0
  48. package/.claude/worktrees/agent-a0a8dd02/native/macos/src-tauri/icons/128x128@2x.png +0 -0
  49. package/.claude/worktrees/agent-a0a8dd02/native/macos/src-tauri/icons/32x32.png +0 -0
  50. package/.claude/worktrees/agent-a0a8dd02/native/macos/src-tauri/icons/icon.icns +0 -0
  51. package/.claude/worktrees/agent-a0a8dd02/native/macos/src-tauri/icons/tray-connected.png +0 -0
  52. package/.claude/worktrees/agent-a0a8dd02/native/macos/src-tauri/icons/tray-disconnected.png +0 -0
  53. package/.claude/worktrees/agent-a0a8dd02/native/macos/src-tauri/src/discovery.rs +184 -0
  54. package/.claude/worktrees/agent-a0a8dd02/native/macos/src-tauri/src/health.rs +67 -0
  55. package/.claude/worktrees/agent-a0a8dd02/native/macos/src-tauri/src/lib.rs +256 -0
  56. package/.claude/worktrees/agent-a0a8dd02/native/macos/src-tauri/src/main.rs +6 -0
  57. package/.claude/worktrees/agent-a0a8dd02/native/macos/src-tauri/src/notifications.rs +180 -0
  58. package/.claude/worktrees/agent-a0a8dd02/native/macos/src-tauri/src/server.rs +306 -0
  59. package/.claude/worktrees/agent-a0a8dd02/native/macos/src-tauri/src/updater.rs +124 -0
  60. package/.claude/worktrees/agent-a0a8dd02/native/macos/src-tauri/tauri.conf.json +58 -0
  61. package/.claude/worktrees/agent-a0a8dd02/package.json +54 -0
  62. package/.claude/worktrees/agent-a0a8dd02/pkg.config.json +14 -0
  63. package/.claude/worktrees/agent-a0a8dd02/scripts/build-standalone.sh +106 -0
  64. package/.claude/worktrees/agent-a0a8dd02/scripts/cleanup.js +251 -0
  65. package/.claude/worktrees/agent-a0a8dd02/scripts/generate-update-manifest.sh +42 -0
  66. package/.claude/worktrees/agent-a0a8dd02/scripts/install-openclaw.js +986 -0
  67. package/.claude/worktrees/agent-a0a8dd02/scripts/install-skills.js +234 -0
  68. package/.claude/worktrees/agent-a0a8dd02/scripts/postinstall.js +224 -0
  69. package/.claude/worktrees/agent-a0a8dd02/scripts/preuninstall.js +68 -0
  70. package/.claude/worktrees/agent-a0a8dd02/scripts/run-e2e.sh +44 -0
  71. package/.claude/worktrees/agent-a0a8dd02/scripts/smoke-test-standalone.sh +101 -0
  72. package/.claude/worktrees/agent-a0a8dd02/scripts/sync-version.sh +28 -0
  73. package/.claude/worktrees/agent-a0a8dd02/scripts/verify-app-bundle.sh +34 -0
  74. package/.claude/worktrees/agent-a0a8dd02/src/dashboard/public/app.js +2683 -0
  75. package/.claude/worktrees/agent-a0a8dd02/src/dashboard/public/index.html +393 -0
  76. package/.claude/worktrees/agent-a0a8dd02/src/dashboard/public/style.css +1294 -0
  77. package/.claude/worktrees/agent-a0a8dd02/src/index.js +76 -0
  78. package/.claude/worktrees/agent-a0a8dd02/src/lib/agent-card.js +111 -0
  79. package/.claude/worktrees/agent-a0a8dd02/src/lib/call-monitor.js +205 -0
  80. package/.claude/worktrees/agent-a0a8dd02/src/lib/callbook.js +366 -0
  81. package/.claude/worktrees/agent-a0a8dd02/src/lib/claude-subagent.js +696 -0
  82. package/.claude/worktrees/agent-a0a8dd02/src/lib/client.js +683 -0
  83. package/.claude/worktrees/agent-a0a8dd02/src/lib/config.js +480 -0
  84. package/.claude/worktrees/agent-a0a8dd02/src/lib/conversation-driver.js +608 -0
  85. package/.claude/worktrees/agent-a0a8dd02/src/lib/conversations.js +830 -0
  86. package/.claude/worktrees/agent-a0a8dd02/src/lib/crypto.js +113 -0
  87. package/.claude/worktrees/agent-a0a8dd02/src/lib/dashboard-events.js +213 -0
  88. package/.claude/worktrees/agent-a0a8dd02/src/lib/disclosure.js +792 -0
  89. package/.claude/worktrees/agent-a0a8dd02/src/lib/external-ip.js +211 -0
  90. package/.claude/worktrees/agent-a0a8dd02/src/lib/invite-host.js +223 -0
  91. package/.claude/worktrees/agent-a0a8dd02/src/lib/local-request.js +69 -0
  92. package/.claude/worktrees/agent-a0a8dd02/src/lib/logger.js +677 -0
  93. package/.claude/worktrees/agent-a0a8dd02/src/lib/openclaw-integration.js +339 -0
  94. package/.claude/worktrees/agent-a0a8dd02/src/lib/pid-file.js +103 -0
  95. package/.claude/worktrees/agent-a0a8dd02/src/lib/port-scanner.js +83 -0
  96. package/.claude/worktrees/agent-a0a8dd02/src/lib/prompt-template.js +355 -0
  97. package/.claude/worktrees/agent-a0a8dd02/src/lib/runtime-adapter.js +701 -0
  98. package/.claude/worktrees/agent-a0a8dd02/src/lib/summarizer.js +156 -0
  99. package/.claude/worktrees/agent-a0a8dd02/src/lib/summary-formatter.js +168 -0
  100. package/.claude/worktrees/agent-a0a8dd02/src/lib/summary-prompt.js +203 -0
  101. package/.claude/worktrees/agent-a0a8dd02/src/lib/tokens.js +868 -0
  102. package/.claude/worktrees/agent-a0a8dd02/src/lib/turn-timeout.js +52 -0
  103. package/.claude/worktrees/agent-a0a8dd02/src/lib/update-checker.js +93 -0
  104. package/.claude/worktrees/agent-a0a8dd02/src/lib/update-manager.js +313 -0
  105. package/.claude/worktrees/agent-a0a8dd02/src/routes/a2a.js +1213 -0
  106. package/.claude/worktrees/agent-a0a8dd02/src/routes/callbook.js +142 -0
  107. package/.claude/worktrees/agent-a0a8dd02/src/routes/dashboard.js +1578 -0
  108. package/.claude/worktrees/agent-a0a8dd02/src/server.js +1179 -0
  109. package/.claude/worktrees/agent-a3c12538/.a2a-manifest.json +70 -0
  110. package/.claude/worktrees/agent-a3c12538/.c8rc.json +16 -0
  111. package/.claude/worktrees/agent-a3c12538/.claude/a2a-skill-reference.md +462 -0
  112. package/.claude/worktrees/agent-a3c12538/.claude/commands/a2a-app.md +42 -0
  113. package/.claude/worktrees/agent-a3c12538/.claude/commands/a2a-call.md +26 -0
  114. package/.claude/worktrees/agent-a3c12538/.claude/commands/a2a-contacts.md +31 -0
  115. package/.claude/worktrees/agent-a3c12538/.claude/commands/a2a-conversations.md +47 -0
  116. package/.claude/worktrees/agent-a3c12538/.claude/commands/a2a-gui.md +30 -0
  117. package/.claude/worktrees/agent-a3c12538/.claude/commands/a2a-invite.md +63 -0
  118. package/.claude/worktrees/agent-a3c12538/.claude/commands/a2a-setup.md +30 -0
  119. package/.claude/worktrees/agent-a3c12538/.claude/commands/a2a-skills.md +27 -0
  120. package/.claude/worktrees/agent-a3c12538/.claude/commands/a2a-status.md +46 -0
  121. package/.claude/worktrees/agent-a3c12538/.claude/commands/a2a-uninstall.md +36 -0
  122. package/.claude/worktrees/agent-a3c12538/.claude/commands/a2a-update.md +41 -0
  123. package/.claude/worktrees/agent-a3c12538/.node-version +1 -0
  124. package/.claude/worktrees/agent-a3c12538/ARCHITECTURE.md +135 -0
  125. package/.claude/worktrees/agent-a3c12538/CLAUDE-INSTALL.md +156 -0
  126. package/.claude/worktrees/agent-a3c12538/CONVENTIONS.md +169 -0
  127. package/.claude/worktrees/agent-a3c12538/README.md +470 -0
  128. package/.claude/worktrees/agent-a3c12538/SKILL.md +462 -0
  129. package/.claude/worktrees/agent-a3c12538/bin/cli.js +3184 -0
  130. package/.claude/worktrees/agent-a3c12538/biome.json +27 -0
  131. package/.claude/worktrees/agent-a3c12538/docs/app.js +30 -0
  132. package/.claude/worktrees/agent-a3c12538/docs/assessments/2026-02-27-google-a2a-protocol-assessment.md +292 -0
  133. package/.claude/worktrees/agent-a3c12538/docs/assets/icon-32.png +0 -0
  134. package/.claude/worktrees/agent-a3c12538/docs/assets/icon-64.png +0 -0
  135. package/.claude/worktrees/agent-a3c12538/docs/index.html +117 -0
  136. package/.claude/worktrees/agent-a3c12538/docs/plans/2026-02-15-port-fallback-warning-design.md +611 -0
  137. package/.claude/worktrees/agent-a3c12538/docs/plans/2026-02-16-a2a-callbook-macos-app.md +1660 -0
  138. package/.claude/worktrees/agent-a3c12538/docs/plans/2026-02-16-auto-updater.md +1284 -0
  139. package/.claude/worktrees/agent-a3c12538/docs/plans/2026-02-16-bugfixes-22-24.md +246 -0
  140. package/.claude/worktrees/agent-a3c12538/docs/plans/2026-02-16-e2e-test-prompt-sequence.md +3085 -0
  141. package/.claude/worktrees/agent-a3c12538/docs/plans/2026-02-16-orphan-process-fix.md +962 -0
  142. package/.claude/worktrees/agent-a3c12538/docs/plans/2026-02-17-claude-code-codex-skills.md +770 -0
  143. package/.claude/worktrees/agent-a3c12538/docs/plans/2026-03-01-a2a-68-openclaw-integration-tests.md +676 -0
  144. package/.claude/worktrees/agent-a3c12538/docs/plans/2026-03-01-a2a-77-invoke-security-tests.md +661 -0
  145. package/.claude/worktrees/agent-a3c12538/docs/prompts/e2e-test-agent.md +368 -0
  146. package/.claude/worktrees/agent-a3c12538/docs/protocol.md +440 -0
  147. package/.claude/worktrees/agent-a3c12538/docs/signing-setup.md +49 -0
  148. package/.claude/worktrees/agent-a3c12538/docs/style.css +209 -0
  149. package/.claude/worktrees/agent-a3c12538/eslint.config.js +16 -0
  150. package/.claude/worktrees/agent-a3c12538/knip.json +17 -0
  151. package/.claude/worktrees/agent-a3c12538/native/macos/index.html +179 -0
  152. package/.claude/worktrees/agent-a3c12538/native/macos/package.json +8 -0
  153. package/.claude/worktrees/agent-a3c12538/native/macos/src-tauri/Cargo.lock +5875 -0
  154. package/.claude/worktrees/agent-a3c12538/native/macos/src-tauri/Cargo.toml +24 -0
  155. package/.claude/worktrees/agent-a3c12538/native/macos/src-tauri/binaries/.gitkeep +0 -0
  156. package/.claude/worktrees/agent-a3c12538/native/macos/src-tauri/build.rs +3 -0
  157. package/.claude/worktrees/agent-a3c12538/native/macos/src-tauri/capabilities/default.json +26 -0
  158. package/.claude/worktrees/agent-a3c12538/native/macos/src-tauri/entitlements.plist +14 -0
  159. package/.claude/worktrees/agent-a3c12538/native/macos/src-tauri/icons/128x128.png +0 -0
  160. package/.claude/worktrees/agent-a3c12538/native/macos/src-tauri/icons/128x128@2x.png +0 -0
  161. package/.claude/worktrees/agent-a3c12538/native/macos/src-tauri/icons/32x32.png +0 -0
  162. package/.claude/worktrees/agent-a3c12538/native/macos/src-tauri/icons/icon.icns +0 -0
  163. package/.claude/worktrees/agent-a3c12538/native/macos/src-tauri/icons/tray-connected.png +0 -0
  164. package/.claude/worktrees/agent-a3c12538/native/macos/src-tauri/icons/tray-disconnected.png +0 -0
  165. package/.claude/worktrees/agent-a3c12538/native/macos/src-tauri/src/discovery.rs +184 -0
  166. package/.claude/worktrees/agent-a3c12538/native/macos/src-tauri/src/health.rs +67 -0
  167. package/.claude/worktrees/agent-a3c12538/native/macos/src-tauri/src/lib.rs +226 -0
  168. package/.claude/worktrees/agent-a3c12538/native/macos/src-tauri/src/main.rs +6 -0
  169. package/.claude/worktrees/agent-a3c12538/native/macos/src-tauri/src/notifications.rs +180 -0
  170. package/.claude/worktrees/agent-a3c12538/native/macos/src-tauri/src/server.rs +306 -0
  171. package/.claude/worktrees/agent-a3c12538/native/macos/src-tauri/tauri.conf.json +50 -0
  172. package/.claude/worktrees/agent-a3c12538/package.json +54 -0
  173. package/.claude/worktrees/agent-a3c12538/pkg.config.json +14 -0
  174. package/.claude/worktrees/agent-a3c12538/scripts/build-standalone.sh +106 -0
  175. package/.claude/worktrees/agent-a3c12538/scripts/cleanup.js +251 -0
  176. package/.claude/worktrees/agent-a3c12538/scripts/install-openclaw.js +986 -0
  177. package/.claude/worktrees/agent-a3c12538/scripts/install-skills.js +234 -0
  178. package/.claude/worktrees/agent-a3c12538/scripts/postinstall.js +224 -0
  179. package/.claude/worktrees/agent-a3c12538/scripts/preuninstall.js +68 -0
  180. package/.claude/worktrees/agent-a3c12538/scripts/run-e2e.sh +44 -0
  181. package/.claude/worktrees/agent-a3c12538/scripts/smoke-test-standalone.sh +101 -0
  182. package/.claude/worktrees/agent-a3c12538/scripts/sync-version.sh +28 -0
  183. package/.claude/worktrees/agent-a3c12538/scripts/verify-app-bundle.sh +34 -0
  184. package/.claude/worktrees/agent-a3c12538/src/dashboard/public/app.js +2649 -0
  185. package/.claude/worktrees/agent-a3c12538/src/dashboard/public/index.html +386 -0
  186. package/.claude/worktrees/agent-a3c12538/src/dashboard/public/style.css +1274 -0
  187. package/.claude/worktrees/agent-a3c12538/src/index.js +76 -0
  188. package/.claude/worktrees/agent-a3c12538/src/lib/agent-card.js +111 -0
  189. package/.claude/worktrees/agent-a3c12538/src/lib/call-monitor.js +205 -0
  190. package/.claude/worktrees/agent-a3c12538/src/lib/callbook.js +366 -0
  191. package/.claude/worktrees/agent-a3c12538/src/lib/claude-subagent.js +696 -0
  192. package/.claude/worktrees/agent-a3c12538/src/lib/client.js +683 -0
  193. package/.claude/worktrees/agent-a3c12538/src/lib/config.js +480 -0
  194. package/.claude/worktrees/agent-a3c12538/src/lib/conversation-driver.js +608 -0
  195. package/.claude/worktrees/agent-a3c12538/src/lib/conversations.js +830 -0
  196. package/.claude/worktrees/agent-a3c12538/src/lib/crypto.js +113 -0
  197. package/.claude/worktrees/agent-a3c12538/src/lib/dashboard-events.js +213 -0
  198. package/.claude/worktrees/agent-a3c12538/src/lib/disclosure.js +792 -0
  199. package/.claude/worktrees/agent-a3c12538/src/lib/external-ip.js +211 -0
  200. package/.claude/worktrees/agent-a3c12538/src/lib/invite-host.js +223 -0
  201. package/.claude/worktrees/agent-a3c12538/src/lib/local-request.js +69 -0
  202. package/.claude/worktrees/agent-a3c12538/src/lib/logger.js +677 -0
  203. package/.claude/worktrees/agent-a3c12538/src/lib/openclaw-integration.js +339 -0
  204. package/.claude/worktrees/agent-a3c12538/src/lib/pid-file.js +103 -0
  205. package/.claude/worktrees/agent-a3c12538/src/lib/port-scanner.js +83 -0
  206. package/.claude/worktrees/agent-a3c12538/src/lib/prompt-template.js +355 -0
  207. package/.claude/worktrees/agent-a3c12538/src/lib/runtime-adapter.js +701 -0
  208. package/.claude/worktrees/agent-a3c12538/src/lib/summarizer.js +156 -0
  209. package/.claude/worktrees/agent-a3c12538/src/lib/summary-formatter.js +168 -0
  210. package/.claude/worktrees/agent-a3c12538/src/lib/summary-prompt.js +203 -0
  211. package/.claude/worktrees/agent-a3c12538/src/lib/tokens.js +868 -0
  212. package/.claude/worktrees/agent-a3c12538/src/lib/turn-timeout.js +52 -0
  213. package/.claude/worktrees/agent-a3c12538/src/lib/update-checker.js +93 -0
  214. package/.claude/worktrees/agent-a3c12538/src/lib/update-manager.js +313 -0
  215. package/.claude/worktrees/agent-a3c12538/src/routes/a2a.js +1213 -0
  216. package/.claude/worktrees/agent-a3c12538/src/routes/callbook.js +142 -0
  217. package/.claude/worktrees/agent-a3c12538/src/routes/dashboard.js +1578 -0
  218. package/.claude/worktrees/agent-a3c12538/src/server.js +1179 -0
  219. package/.claude/worktrees/agent-a5b87d75/.a2a-manifest.json +70 -0
  220. package/.claude/worktrees/agent-a5b87d75/.c8rc.json +16 -0
  221. package/.claude/worktrees/agent-a5b87d75/.claude/a2a-skill-reference.md +462 -0
  222. package/.claude/worktrees/agent-a5b87d75/.claude/commands/a2a-app.md +42 -0
  223. package/.claude/worktrees/agent-a5b87d75/.claude/commands/a2a-call.md +26 -0
  224. package/.claude/worktrees/agent-a5b87d75/.claude/commands/a2a-contacts.md +31 -0
  225. package/.claude/worktrees/agent-a5b87d75/.claude/commands/a2a-conversations.md +47 -0
  226. package/.claude/worktrees/agent-a5b87d75/.claude/commands/a2a-gui.md +30 -0
  227. package/.claude/worktrees/agent-a5b87d75/.claude/commands/a2a-invite.md +63 -0
  228. package/.claude/worktrees/agent-a5b87d75/.claude/commands/a2a-setup.md +30 -0
  229. package/.claude/worktrees/agent-a5b87d75/.claude/commands/a2a-skills.md +27 -0
  230. package/.claude/worktrees/agent-a5b87d75/.claude/commands/a2a-status.md +46 -0
  231. package/.claude/worktrees/agent-a5b87d75/.claude/commands/a2a-uninstall.md +36 -0
  232. package/.claude/worktrees/agent-a5b87d75/.claude/commands/a2a-update.md +41 -0
  233. package/.claude/worktrees/agent-a5b87d75/.node-version +1 -0
  234. package/.claude/worktrees/agent-a5b87d75/ARCHITECTURE.md +135 -0
  235. package/.claude/worktrees/agent-a5b87d75/CLAUDE-INSTALL.md +156 -0
  236. package/.claude/worktrees/agent-a5b87d75/CONVENTIONS.md +208 -0
  237. package/.claude/worktrees/agent-a5b87d75/README.md +470 -0
  238. package/.claude/worktrees/agent-a5b87d75/SKILL.md +462 -0
  239. package/.claude/worktrees/agent-a5b87d75/bin/cli.js +3184 -0
  240. package/.claude/worktrees/agent-a5b87d75/biome.json +27 -0
  241. package/.claude/worktrees/agent-a5b87d75/docs/app.js +30 -0
  242. package/.claude/worktrees/agent-a5b87d75/docs/assessments/2026-02-27-google-a2a-protocol-assessment.md +292 -0
  243. package/.claude/worktrees/agent-a5b87d75/docs/assets/icon-32.png +0 -0
  244. package/.claude/worktrees/agent-a5b87d75/docs/assets/icon-64.png +0 -0
  245. package/.claude/worktrees/agent-a5b87d75/docs/index.html +117 -0
  246. package/.claude/worktrees/agent-a5b87d75/docs/plans/2026-02-15-port-fallback-warning-design.md +611 -0
  247. package/.claude/worktrees/agent-a5b87d75/docs/plans/2026-02-16-a2a-callbook-macos-app.md +1660 -0
  248. package/.claude/worktrees/agent-a5b87d75/docs/plans/2026-02-16-auto-updater.md +1284 -0
  249. package/.claude/worktrees/agent-a5b87d75/docs/plans/2026-02-16-bugfixes-22-24.md +246 -0
  250. package/.claude/worktrees/agent-a5b87d75/docs/plans/2026-02-16-e2e-test-prompt-sequence.md +3085 -0
  251. package/.claude/worktrees/agent-a5b87d75/docs/plans/2026-02-16-orphan-process-fix.md +962 -0
  252. package/.claude/worktrees/agent-a5b87d75/docs/plans/2026-02-17-claude-code-codex-skills.md +770 -0
  253. package/.claude/worktrees/agent-a5b87d75/docs/plans/2026-03-01-a2a-68-openclaw-integration-tests.md +676 -0
  254. package/.claude/worktrees/agent-a5b87d75/docs/plans/2026-03-01-a2a-77-invoke-security-tests.md +661 -0
  255. package/.claude/worktrees/agent-a5b87d75/docs/prompts/e2e-test-agent.md +368 -0
  256. package/.claude/worktrees/agent-a5b87d75/docs/protocol.md +440 -0
  257. package/.claude/worktrees/agent-a5b87d75/docs/signing-setup.md +49 -0
  258. package/.claude/worktrees/agent-a5b87d75/docs/style.css +209 -0
  259. package/.claude/worktrees/agent-a5b87d75/eslint.config.js +16 -0
  260. package/.claude/worktrees/agent-a5b87d75/knip.json +17 -0
  261. package/.claude/worktrees/agent-a5b87d75/native/macos/index.html +182 -0
  262. package/.claude/worktrees/agent-a5b87d75/native/macos/package.json +8 -0
  263. package/.claude/worktrees/agent-a5b87d75/native/macos/src-tauri/Cargo.lock +5875 -0
  264. package/.claude/worktrees/agent-a5b87d75/native/macos/src-tauri/Cargo.toml +25 -0
  265. package/.claude/worktrees/agent-a5b87d75/native/macos/src-tauri/binaries/.gitkeep +0 -0
  266. package/.claude/worktrees/agent-a5b87d75/native/macos/src-tauri/build.rs +3 -0
  267. package/.claude/worktrees/agent-a5b87d75/native/macos/src-tauri/capabilities/default.json +26 -0
  268. package/.claude/worktrees/agent-a5b87d75/native/macos/src-tauri/dmg-background.png +0 -0
  269. package/.claude/worktrees/agent-a5b87d75/native/macos/src-tauri/dmg-background@2x.png +0 -0
  270. package/.claude/worktrees/agent-a5b87d75/native/macos/src-tauri/entitlements.plist +14 -0
  271. package/.claude/worktrees/agent-a5b87d75/native/macos/src-tauri/icons/128x128.png +0 -0
  272. package/.claude/worktrees/agent-a5b87d75/native/macos/src-tauri/icons/128x128@2x.png +0 -0
  273. package/.claude/worktrees/agent-a5b87d75/native/macos/src-tauri/icons/256x256.png +0 -0
  274. package/.claude/worktrees/agent-a5b87d75/native/macos/src-tauri/icons/32x32.png +0 -0
  275. package/.claude/worktrees/agent-a5b87d75/native/macos/src-tauri/icons/512x512.png +0 -0
  276. package/.claude/worktrees/agent-a5b87d75/native/macos/src-tauri/icons/512x512@2x.png +0 -0
  277. package/.claude/worktrees/agent-a5b87d75/native/macos/src-tauri/icons/icon.icns +0 -0
  278. package/.claude/worktrees/agent-a5b87d75/native/macos/src-tauri/icons/tray-connected.png +0 -0
  279. package/.claude/worktrees/agent-a5b87d75/native/macos/src-tauri/icons/tray-disconnected.png +0 -0
  280. package/.claude/worktrees/agent-a5b87d75/native/macos/src-tauri/src/discovery.rs +221 -0
  281. package/.claude/worktrees/agent-a5b87d75/native/macos/src-tauri/src/health.rs +67 -0
  282. package/.claude/worktrees/agent-a5b87d75/native/macos/src-tauri/src/lib.rs +256 -0
  283. package/.claude/worktrees/agent-a5b87d75/native/macos/src-tauri/src/main.rs +6 -0
  284. package/.claude/worktrees/agent-a5b87d75/native/macos/src-tauri/src/notifications.rs +180 -0
  285. package/.claude/worktrees/agent-a5b87d75/native/macos/src-tauri/src/server.rs +306 -0
  286. package/.claude/worktrees/agent-a5b87d75/native/macos/src-tauri/src/updater.rs +124 -0
  287. package/.claude/worktrees/agent-a5b87d75/native/macos/src-tauri/tauri.conf.json +68 -0
  288. package/.claude/worktrees/agent-a5b87d75/native/macos/src-tauri/volume-icon.icns +0 -0
  289. package/.claude/worktrees/agent-a5b87d75/package.json +55 -0
  290. package/.claude/worktrees/agent-a5b87d75/pkg.config.json +14 -0
  291. package/.claude/worktrees/agent-a5b87d75/scripts/build-standalone.sh +106 -0
  292. package/.claude/worktrees/agent-a5b87d75/scripts/cleanup.js +251 -0
  293. package/.claude/worktrees/agent-a5b87d75/scripts/generate-update-manifest.sh +42 -0
  294. package/.claude/worktrees/agent-a5b87d75/scripts/install-openclaw.js +986 -0
  295. package/.claude/worktrees/agent-a5b87d75/scripts/install-skills.js +234 -0
  296. package/.claude/worktrees/agent-a5b87d75/scripts/postinstall.js +224 -0
  297. package/.claude/worktrees/agent-a5b87d75/scripts/preuninstall.js +68 -0
  298. package/.claude/worktrees/agent-a5b87d75/scripts/run-e2e.sh +52 -0
  299. package/.claude/worktrees/agent-a5b87d75/scripts/smoke-test-standalone.sh +101 -0
  300. package/.claude/worktrees/agent-a5b87d75/scripts/sync-version.sh +28 -0
  301. package/.claude/worktrees/agent-a5b87d75/scripts/verify-app-bundle.sh +34 -0
  302. package/.claude/worktrees/agent-a5b87d75/src/dashboard/public/app.js +2683 -0
  303. package/.claude/worktrees/agent-a5b87d75/src/dashboard/public/index.html +393 -0
  304. package/.claude/worktrees/agent-a5b87d75/src/dashboard/public/onboarding.css +269 -0
  305. package/.claude/worktrees/agent-a5b87d75/src/dashboard/public/onboarding.html +96 -0
  306. package/.claude/worktrees/agent-a5b87d75/src/dashboard/public/onboarding.js +277 -0
  307. package/.claude/worktrees/agent-a5b87d75/src/dashboard/public/style.css +1294 -0
  308. package/.claude/worktrees/agent-a5b87d75/src/index.js +76 -0
  309. package/.claude/worktrees/agent-a5b87d75/src/lib/agent-card.js +111 -0
  310. package/.claude/worktrees/agent-a5b87d75/src/lib/call-monitor.js +205 -0
  311. package/.claude/worktrees/agent-a5b87d75/src/lib/callbook.js +366 -0
  312. package/.claude/worktrees/agent-a5b87d75/src/lib/claude-subagent.js +696 -0
  313. package/.claude/worktrees/agent-a5b87d75/src/lib/client.js +683 -0
  314. package/.claude/worktrees/agent-a5b87d75/src/lib/config.js +480 -0
  315. package/.claude/worktrees/agent-a5b87d75/src/lib/conversation-driver.js +608 -0
  316. package/.claude/worktrees/agent-a5b87d75/src/lib/conversations.js +830 -0
  317. package/.claude/worktrees/agent-a5b87d75/src/lib/crypto.js +113 -0
  318. package/.claude/worktrees/agent-a5b87d75/src/lib/dashboard-events.js +213 -0
  319. package/.claude/worktrees/agent-a5b87d75/src/lib/disclosure.js +792 -0
  320. package/.claude/worktrees/agent-a5b87d75/src/lib/external-ip.js +211 -0
  321. package/.claude/worktrees/agent-a5b87d75/src/lib/invite-host.js +223 -0
  322. package/.claude/worktrees/agent-a5b87d75/src/lib/local-request.js +69 -0
  323. package/.claude/worktrees/agent-a5b87d75/src/lib/logger.js +677 -0
  324. package/.claude/worktrees/agent-a5b87d75/src/lib/openclaw-integration.js +339 -0
  325. package/.claude/worktrees/agent-a5b87d75/src/lib/pid-file.js +103 -0
  326. package/.claude/worktrees/agent-a5b87d75/src/lib/port-scanner.js +83 -0
  327. package/.claude/worktrees/agent-a5b87d75/src/lib/prompt-template.js +355 -0
  328. package/.claude/worktrees/agent-a5b87d75/src/lib/runtime-adapter.js +701 -0
  329. package/.claude/worktrees/agent-a5b87d75/src/lib/summarizer.js +156 -0
  330. package/.claude/worktrees/agent-a5b87d75/src/lib/summary-formatter.js +168 -0
  331. package/.claude/worktrees/agent-a5b87d75/src/lib/summary-prompt.js +203 -0
  332. package/.claude/worktrees/agent-a5b87d75/src/lib/tokens.js +868 -0
  333. package/.claude/worktrees/agent-a5b87d75/src/lib/turn-timeout.js +52 -0
  334. package/.claude/worktrees/agent-a5b87d75/src/lib/update-checker.js +93 -0
  335. package/.claude/worktrees/agent-a5b87d75/src/lib/update-manager.js +313 -0
  336. package/.claude/worktrees/agent-a5b87d75/src/routes/a2a.js +1213 -0
  337. package/.claude/worktrees/agent-a5b87d75/src/routes/callbook.js +142 -0
  338. package/.claude/worktrees/agent-a5b87d75/src/routes/dashboard.js +1688 -0
  339. package/.claude/worktrees/agent-a5b87d75/src/server.js +1179 -0
  340. package/.claude/worktrees/agent-acefedbd/.a2a-manifest.json +70 -0
  341. package/.claude/worktrees/agent-acefedbd/.c8rc.json +16 -0
  342. package/.claude/worktrees/agent-acefedbd/.claude/a2a-skill-reference.md +462 -0
  343. package/.claude/worktrees/agent-acefedbd/.claude/commands/a2a-app.md +42 -0
  344. package/.claude/worktrees/agent-acefedbd/.claude/commands/a2a-call.md +26 -0
  345. package/.claude/worktrees/agent-acefedbd/.claude/commands/a2a-contacts.md +31 -0
  346. package/.claude/worktrees/agent-acefedbd/.claude/commands/a2a-conversations.md +47 -0
  347. package/.claude/worktrees/agent-acefedbd/.claude/commands/a2a-gui.md +30 -0
  348. package/.claude/worktrees/agent-acefedbd/.claude/commands/a2a-invite.md +63 -0
  349. package/.claude/worktrees/agent-acefedbd/.claude/commands/a2a-setup.md +30 -0
  350. package/.claude/worktrees/agent-acefedbd/.claude/commands/a2a-skills.md +27 -0
  351. package/.claude/worktrees/agent-acefedbd/.claude/commands/a2a-status.md +46 -0
  352. package/.claude/worktrees/agent-acefedbd/.claude/commands/a2a-uninstall.md +36 -0
  353. package/.claude/worktrees/agent-acefedbd/.claude/commands/a2a-update.md +41 -0
  354. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/.a2a-manifest.json +70 -0
  355. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/.c8rc.json +16 -0
  356. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/.claude/a2a-skill-reference.md +462 -0
  357. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/.claude/commands/a2a-app.md +42 -0
  358. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/.claude/commands/a2a-call.md +26 -0
  359. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/.claude/commands/a2a-contacts.md +31 -0
  360. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/.claude/commands/a2a-conversations.md +47 -0
  361. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/.claude/commands/a2a-gui.md +30 -0
  362. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/.claude/commands/a2a-invite.md +63 -0
  363. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/.claude/commands/a2a-setup.md +30 -0
  364. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/.claude/commands/a2a-skills.md +27 -0
  365. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/.claude/commands/a2a-status.md +46 -0
  366. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/.claude/commands/a2a-uninstall.md +36 -0
  367. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/.claude/commands/a2a-update.md +41 -0
  368. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/.node-version +1 -0
  369. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/ARCHITECTURE.md +135 -0
  370. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/CLAUDE-INSTALL.md +156 -0
  371. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/CONVENTIONS.md +179 -0
  372. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/README.md +470 -0
  373. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/SKILL.md +462 -0
  374. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/bin/cli.js +3184 -0
  375. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/biome.json +27 -0
  376. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/docs/assessments/2026-02-27-google-a2a-protocol-assessment.md +292 -0
  377. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/docs/plans/2026-02-15-port-fallback-warning-design.md +611 -0
  378. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/docs/plans/2026-02-16-a2a-callbook-macos-app.md +1660 -0
  379. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/docs/plans/2026-02-16-auto-updater.md +1284 -0
  380. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/docs/plans/2026-02-16-bugfixes-22-24.md +246 -0
  381. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/docs/plans/2026-02-16-e2e-test-prompt-sequence.md +3085 -0
  382. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/docs/plans/2026-02-16-orphan-process-fix.md +962 -0
  383. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/docs/plans/2026-02-17-claude-code-codex-skills.md +770 -0
  384. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/docs/plans/2026-03-01-a2a-68-openclaw-integration-tests.md +676 -0
  385. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/docs/plans/2026-03-01-a2a-77-invoke-security-tests.md +661 -0
  386. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/docs/prompts/e2e-test-agent.md +368 -0
  387. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/docs/protocol.md +440 -0
  388. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/docs/signing-setup.md +49 -0
  389. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/eslint.config.js +16 -0
  390. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/knip.json +17 -0
  391. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/native/macos/index.html +179 -0
  392. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/native/macos/package.json +8 -0
  393. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/native/macos/src-tauri/Cargo.lock +5875 -0
  394. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/native/macos/src-tauri/Cargo.toml +25 -0
  395. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/native/macos/src-tauri/binaries/.gitkeep +0 -0
  396. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/native/macos/src-tauri/build.rs +3 -0
  397. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/native/macos/src-tauri/capabilities/default.json +26 -0
  398. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/native/macos/src-tauri/entitlements.plist +14 -0
  399. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/native/macos/src-tauri/icons/128x128.png +0 -0
  400. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/native/macos/src-tauri/icons/128x128@2x.png +0 -0
  401. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/native/macos/src-tauri/icons/32x32.png +0 -0
  402. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/native/macos/src-tauri/icons/icon.icns +0 -0
  403. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/native/macos/src-tauri/icons/tray-connected.png +0 -0
  404. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/native/macos/src-tauri/icons/tray-disconnected.png +0 -0
  405. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/native/macos/src-tauri/src/discovery.rs +184 -0
  406. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/native/macos/src-tauri/src/health.rs +67 -0
  407. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/native/macos/src-tauri/src/lib.rs +255 -0
  408. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/native/macos/src-tauri/src/main.rs +6 -0
  409. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/native/macos/src-tauri/src/notifications.rs +180 -0
  410. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/native/macos/src-tauri/src/server.rs +306 -0
  411. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/native/macos/src-tauri/src/updater.rs +117 -0
  412. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/native/macos/src-tauri/tauri.conf.json +58 -0
  413. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/package.json +54 -0
  414. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/pkg.config.json +14 -0
  415. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/scripts/build-standalone.sh +106 -0
  416. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/scripts/cleanup.js +251 -0
  417. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/scripts/generate-update-manifest.sh +42 -0
  418. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/scripts/install-openclaw.js +986 -0
  419. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/scripts/install-skills.js +234 -0
  420. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/scripts/postinstall.js +224 -0
  421. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/scripts/preuninstall.js +68 -0
  422. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/scripts/run-e2e.sh +44 -0
  423. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/scripts/smoke-test-standalone.sh +101 -0
  424. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/scripts/sync-version.sh +28 -0
  425. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/scripts/verify-app-bundle.sh +34 -0
  426. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/dashboard/public/app.js +2683 -0
  427. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/dashboard/public/index.html +394 -0
  428. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/dashboard/public/style.css +1294 -0
  429. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/index.js +76 -0
  430. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/lib/agent-card.js +111 -0
  431. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/lib/call-monitor.js +205 -0
  432. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/lib/callbook.js +366 -0
  433. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/lib/claude-subagent.js +696 -0
  434. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/lib/client.js +683 -0
  435. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/lib/config.js +480 -0
  436. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/lib/conversation-driver.js +608 -0
  437. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/lib/conversations.js +830 -0
  438. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/lib/crypto.js +113 -0
  439. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/lib/dashboard-events.js +213 -0
  440. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/lib/disclosure.js +792 -0
  441. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/lib/external-ip.js +211 -0
  442. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/lib/invite-host.js +223 -0
  443. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/lib/local-request.js +69 -0
  444. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/lib/logger.js +677 -0
  445. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/lib/openclaw-integration.js +339 -0
  446. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/lib/pid-file.js +103 -0
  447. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/lib/port-scanner.js +83 -0
  448. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/lib/prompt-template.js +355 -0
  449. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/lib/runtime-adapter.js +701 -0
  450. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/lib/summarizer.js +156 -0
  451. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/lib/summary-formatter.js +168 -0
  452. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/lib/summary-prompt.js +203 -0
  453. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/lib/tokens.js +868 -0
  454. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/lib/turn-timeout.js +52 -0
  455. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/lib/update-checker.js +93 -0
  456. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/lib/update-manager.js +313 -0
  457. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/routes/a2a.js +1213 -0
  458. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/routes/callbook.js +142 -0
  459. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/routes/dashboard.js +1578 -0
  460. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a04dc0fe/src/server.js +1179 -0
  461. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/.a2a-manifest.json +70 -0
  462. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/.c8rc.json +16 -0
  463. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/.claude/a2a-skill-reference.md +462 -0
  464. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/.claude/commands/a2a-app.md +42 -0
  465. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/.claude/commands/a2a-call.md +26 -0
  466. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/.claude/commands/a2a-contacts.md +31 -0
  467. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/.claude/commands/a2a-conversations.md +47 -0
  468. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/.claude/commands/a2a-gui.md +30 -0
  469. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/.claude/commands/a2a-invite.md +63 -0
  470. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/.claude/commands/a2a-setup.md +30 -0
  471. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/.claude/commands/a2a-skills.md +27 -0
  472. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/.claude/commands/a2a-status.md +46 -0
  473. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/.claude/commands/a2a-uninstall.md +36 -0
  474. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/.claude/commands/a2a-update.md +41 -0
  475. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/.node-version +1 -0
  476. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/ARCHITECTURE.md +135 -0
  477. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/CLAUDE-INSTALL.md +156 -0
  478. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/CONVENTIONS.md +178 -0
  479. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/README.md +470 -0
  480. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/SKILL.md +462 -0
  481. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/bin/cli.js +3184 -0
  482. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/biome.json +27 -0
  483. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/docs/assessments/2026-02-27-google-a2a-protocol-assessment.md +292 -0
  484. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/docs/plans/2026-02-15-port-fallback-warning-design.md +611 -0
  485. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/docs/plans/2026-02-16-a2a-callbook-macos-app.md +1660 -0
  486. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/docs/plans/2026-02-16-auto-updater.md +1284 -0
  487. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/docs/plans/2026-02-16-bugfixes-22-24.md +246 -0
  488. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/docs/plans/2026-02-16-e2e-test-prompt-sequence.md +3085 -0
  489. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/docs/plans/2026-02-16-orphan-process-fix.md +962 -0
  490. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/docs/plans/2026-02-17-claude-code-codex-skills.md +770 -0
  491. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/docs/plans/2026-03-01-a2a-68-openclaw-integration-tests.md +676 -0
  492. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/docs/plans/2026-03-01-a2a-77-invoke-security-tests.md +661 -0
  493. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/docs/prompts/e2e-test-agent.md +368 -0
  494. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/docs/protocol.md +440 -0
  495. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/docs/signing-setup.md +49 -0
  496. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/eslint.config.js +16 -0
  497. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/knip.json +17 -0
  498. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/native/macos/index.html +179 -0
  499. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/native/macos/package.json +8 -0
  500. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/native/macos/src-tauri/Cargo.lock +5875 -0
  501. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/native/macos/src-tauri/Cargo.toml +24 -0
  502. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/native/macos/src-tauri/binaries/.gitkeep +0 -0
  503. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/native/macos/src-tauri/build.rs +3 -0
  504. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/native/macos/src-tauri/capabilities/default.json +26 -0
  505. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/native/macos/src-tauri/dmg-background.png +0 -0
  506. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/native/macos/src-tauri/dmg-background@2x.png +0 -0
  507. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/native/macos/src-tauri/entitlements.plist +14 -0
  508. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/native/macos/src-tauri/icons/128x128.png +0 -0
  509. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/native/macos/src-tauri/icons/128x128@2x.png +0 -0
  510. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/native/macos/src-tauri/icons/256x256.png +0 -0
  511. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/native/macos/src-tauri/icons/32x32.png +0 -0
  512. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/native/macos/src-tauri/icons/512x512.png +0 -0
  513. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/native/macos/src-tauri/icons/512x512@2x.png +0 -0
  514. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/native/macos/src-tauri/icons/icon.icns +0 -0
  515. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/native/macos/src-tauri/icons/tray-connected.png +0 -0
  516. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/native/macos/src-tauri/icons/tray-disconnected.png +0 -0
  517. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/native/macos/src-tauri/src/discovery.rs +184 -0
  518. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/native/macos/src-tauri/src/health.rs +67 -0
  519. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/native/macos/src-tauri/src/lib.rs +226 -0
  520. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/native/macos/src-tauri/src/main.rs +6 -0
  521. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/native/macos/src-tauri/src/notifications.rs +180 -0
  522. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/native/macos/src-tauri/src/server.rs +306 -0
  523. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/native/macos/src-tauri/tauri.conf.json +60 -0
  524. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/native/macos/src-tauri/volume-icon.icns +0 -0
  525. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/package.json +54 -0
  526. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/pkg.config.json +14 -0
  527. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/scripts/build-standalone.sh +106 -0
  528. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/scripts/cleanup.js +251 -0
  529. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/scripts/install-openclaw.js +986 -0
  530. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/scripts/install-skills.js +234 -0
  531. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/scripts/postinstall.js +224 -0
  532. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/scripts/preuninstall.js +68 -0
  533. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/scripts/run-e2e.sh +44 -0
  534. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/scripts/smoke-test-standalone.sh +101 -0
  535. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/scripts/sync-version.sh +28 -0
  536. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/scripts/verify-app-bundle.sh +34 -0
  537. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/dashboard/public/app.js +2649 -0
  538. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/dashboard/public/index.html +386 -0
  539. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/dashboard/public/style.css +1274 -0
  540. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/index.js +76 -0
  541. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/lib/agent-card.js +111 -0
  542. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/lib/call-monitor.js +205 -0
  543. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/lib/callbook.js +366 -0
  544. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/lib/claude-subagent.js +696 -0
  545. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/lib/client.js +683 -0
  546. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/lib/config.js +480 -0
  547. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/lib/conversation-driver.js +608 -0
  548. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/lib/conversations.js +830 -0
  549. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/lib/crypto.js +113 -0
  550. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/lib/dashboard-events.js +213 -0
  551. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/lib/disclosure.js +792 -0
  552. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/lib/external-ip.js +211 -0
  553. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/lib/invite-host.js +223 -0
  554. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/lib/local-request.js +69 -0
  555. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/lib/logger.js +677 -0
  556. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/lib/openclaw-integration.js +339 -0
  557. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/lib/pid-file.js +103 -0
  558. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/lib/port-scanner.js +83 -0
  559. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/lib/prompt-template.js +355 -0
  560. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/lib/runtime-adapter.js +701 -0
  561. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/lib/summarizer.js +156 -0
  562. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/lib/summary-formatter.js +168 -0
  563. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/lib/summary-prompt.js +203 -0
  564. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/lib/tokens.js +868 -0
  565. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/lib/turn-timeout.js +52 -0
  566. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/lib/update-checker.js +93 -0
  567. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/lib/update-manager.js +313 -0
  568. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/routes/a2a.js +1213 -0
  569. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/routes/callbook.js +142 -0
  570. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/routes/dashboard.js +1578 -0
  571. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-a1418bc4/src/server.js +1179 -0
  572. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/.a2a-manifest.json +70 -0
  573. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/.c8rc.json +16 -0
  574. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/.claude/a2a-skill-reference.md +462 -0
  575. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/.claude/commands/a2a-app.md +42 -0
  576. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/.claude/commands/a2a-call.md +26 -0
  577. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/.claude/commands/a2a-contacts.md +31 -0
  578. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/.claude/commands/a2a-conversations.md +47 -0
  579. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/.claude/commands/a2a-gui.md +30 -0
  580. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/.claude/commands/a2a-invite.md +63 -0
  581. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/.claude/commands/a2a-setup.md +30 -0
  582. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/.claude/commands/a2a-skills.md +27 -0
  583. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/.claude/commands/a2a-status.md +46 -0
  584. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/.claude/commands/a2a-uninstall.md +36 -0
  585. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/.claude/commands/a2a-update.md +41 -0
  586. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/.node-version +1 -0
  587. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/ARCHITECTURE.md +135 -0
  588. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/CLAUDE-INSTALL.md +156 -0
  589. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/CONVENTIONS.md +169 -0
  590. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/README.md +470 -0
  591. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/SKILL.md +462 -0
  592. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/bin/cli.js +3184 -0
  593. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/biome.json +27 -0
  594. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/docs/app.js +160 -0
  595. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/docs/assessments/2026-02-27-google-a2a-protocol-assessment.md +292 -0
  596. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/docs/assets/icon-32.png +0 -0
  597. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/docs/assets/icon-64.png +0 -0
  598. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/docs/index.html +166 -0
  599. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/docs/plans/2026-02-15-port-fallback-warning-design.md +611 -0
  600. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/docs/plans/2026-02-16-a2a-callbook-macos-app.md +1660 -0
  601. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/docs/plans/2026-02-16-auto-updater.md +1284 -0
  602. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/docs/plans/2026-02-16-bugfixes-22-24.md +246 -0
  603. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/docs/plans/2026-02-16-e2e-test-prompt-sequence.md +3085 -0
  604. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/docs/plans/2026-02-16-orphan-process-fix.md +962 -0
  605. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/docs/plans/2026-02-17-claude-code-codex-skills.md +770 -0
  606. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/docs/plans/2026-03-01-a2a-68-openclaw-integration-tests.md +676 -0
  607. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/docs/plans/2026-03-01-a2a-77-invoke-security-tests.md +661 -0
  608. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/docs/prompts/e2e-test-agent.md +368 -0
  609. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/docs/protocol.md +440 -0
  610. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/docs/signing-setup.md +49 -0
  611. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/docs/style.css +457 -0
  612. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/eslint.config.js +16 -0
  613. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/knip.json +17 -0
  614. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/native/macos/index.html +179 -0
  615. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/native/macos/package.json +8 -0
  616. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/native/macos/src-tauri/Cargo.lock +5875 -0
  617. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/native/macos/src-tauri/Cargo.toml +24 -0
  618. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/native/macos/src-tauri/binaries/.gitkeep +0 -0
  619. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/native/macos/src-tauri/build.rs +3 -0
  620. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/native/macos/src-tauri/capabilities/default.json +26 -0
  621. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/native/macos/src-tauri/entitlements.plist +14 -0
  622. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/native/macos/src-tauri/icons/128x128.png +0 -0
  623. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/native/macos/src-tauri/icons/128x128@2x.png +0 -0
  624. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/native/macos/src-tauri/icons/32x32.png +0 -0
  625. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/native/macos/src-tauri/icons/icon.icns +0 -0
  626. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/native/macos/src-tauri/icons/tray-connected.png +0 -0
  627. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/native/macos/src-tauri/icons/tray-disconnected.png +0 -0
  628. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/native/macos/src-tauri/src/discovery.rs +184 -0
  629. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/native/macos/src-tauri/src/health.rs +67 -0
  630. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/native/macos/src-tauri/src/lib.rs +226 -0
  631. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/native/macos/src-tauri/src/main.rs +6 -0
  632. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/native/macos/src-tauri/src/notifications.rs +180 -0
  633. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/native/macos/src-tauri/src/server.rs +306 -0
  634. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/native/macos/src-tauri/tauri.conf.json +50 -0
  635. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/package.json +54 -0
  636. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/pkg.config.json +14 -0
  637. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/scripts/build-standalone.sh +106 -0
  638. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/scripts/cleanup.js +251 -0
  639. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/scripts/install-openclaw.js +986 -0
  640. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/scripts/install-skills.js +234 -0
  641. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/scripts/postinstall.js +224 -0
  642. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/scripts/preuninstall.js +68 -0
  643. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/scripts/run-e2e.sh +44 -0
  644. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/scripts/smoke-test-standalone.sh +101 -0
  645. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/scripts/sync-version.sh +28 -0
  646. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/scripts/verify-app-bundle.sh +34 -0
  647. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/dashboard/public/app.js +2649 -0
  648. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/dashboard/public/index.html +386 -0
  649. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/dashboard/public/style.css +1274 -0
  650. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/index.js +76 -0
  651. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/lib/agent-card.js +111 -0
  652. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/lib/call-monitor.js +205 -0
  653. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/lib/callbook.js +366 -0
  654. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/lib/claude-subagent.js +696 -0
  655. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/lib/client.js +683 -0
  656. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/lib/config.js +480 -0
  657. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/lib/conversation-driver.js +608 -0
  658. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/lib/conversations.js +830 -0
  659. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/lib/crypto.js +113 -0
  660. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/lib/dashboard-events.js +213 -0
  661. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/lib/disclosure.js +792 -0
  662. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/lib/external-ip.js +211 -0
  663. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/lib/invite-host.js +223 -0
  664. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/lib/local-request.js +69 -0
  665. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/lib/logger.js +677 -0
  666. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/lib/openclaw-integration.js +339 -0
  667. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/lib/pid-file.js +103 -0
  668. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/lib/port-scanner.js +83 -0
  669. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/lib/prompt-template.js +355 -0
  670. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/lib/runtime-adapter.js +701 -0
  671. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/lib/summarizer.js +156 -0
  672. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/lib/summary-formatter.js +168 -0
  673. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/lib/summary-prompt.js +203 -0
  674. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/lib/tokens.js +868 -0
  675. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/lib/turn-timeout.js +52 -0
  676. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/lib/update-checker.js +93 -0
  677. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/lib/update-manager.js +313 -0
  678. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/routes/a2a.js +1213 -0
  679. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/routes/callbook.js +142 -0
  680. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/routes/dashboard.js +1578 -0
  681. package/.claude/worktrees/agent-acefedbd/.claude/worktrees/agent-aa4cd927/src/server.js +1179 -0
  682. package/.claude/worktrees/agent-acefedbd/.node-version +1 -0
  683. package/.claude/worktrees/agent-acefedbd/ARCHITECTURE.md +135 -0
  684. package/.claude/worktrees/agent-acefedbd/CLAUDE-INSTALL.md +156 -0
  685. package/.claude/worktrees/agent-acefedbd/CONVENTIONS.md +177 -0
  686. package/.claude/worktrees/agent-acefedbd/README.md +470 -0
  687. package/.claude/worktrees/agent-acefedbd/SKILL.md +462 -0
  688. package/.claude/worktrees/agent-acefedbd/bin/cli.js +3184 -0
  689. package/.claude/worktrees/agent-acefedbd/biome.json +27 -0
  690. package/.claude/worktrees/agent-acefedbd/docs/assessments/2026-02-27-google-a2a-protocol-assessment.md +292 -0
  691. package/.claude/worktrees/agent-acefedbd/docs/plans/2026-02-15-port-fallback-warning-design.md +611 -0
  692. package/.claude/worktrees/agent-acefedbd/docs/plans/2026-02-16-a2a-callbook-macos-app.md +1660 -0
  693. package/.claude/worktrees/agent-acefedbd/docs/plans/2026-02-16-auto-updater.md +1284 -0
  694. package/.claude/worktrees/agent-acefedbd/docs/plans/2026-02-16-bugfixes-22-24.md +246 -0
  695. package/.claude/worktrees/agent-acefedbd/docs/plans/2026-02-16-e2e-test-prompt-sequence.md +3085 -0
  696. package/.claude/worktrees/agent-acefedbd/docs/plans/2026-02-16-orphan-process-fix.md +962 -0
  697. package/.claude/worktrees/agent-acefedbd/docs/plans/2026-02-17-claude-code-codex-skills.md +770 -0
  698. package/.claude/worktrees/agent-acefedbd/docs/plans/2026-03-01-a2a-68-openclaw-integration-tests.md +676 -0
  699. package/.claude/worktrees/agent-acefedbd/docs/plans/2026-03-01-a2a-77-invoke-security-tests.md +661 -0
  700. package/.claude/worktrees/agent-acefedbd/docs/prompts/e2e-test-agent.md +368 -0
  701. package/.claude/worktrees/agent-acefedbd/docs/protocol.md +440 -0
  702. package/.claude/worktrees/agent-acefedbd/docs/signing-setup.md +49 -0
  703. package/.claude/worktrees/agent-acefedbd/eslint.config.js +16 -0
  704. package/.claude/worktrees/agent-acefedbd/knip.json +17 -0
  705. package/.claude/worktrees/agent-acefedbd/native/macos/index.html +182 -0
  706. package/.claude/worktrees/agent-acefedbd/native/macos/package.json +8 -0
  707. package/.claude/worktrees/agent-acefedbd/native/macos/src-tauri/Cargo.lock +5875 -0
  708. package/.claude/worktrees/agent-acefedbd/native/macos/src-tauri/Cargo.toml +24 -0
  709. package/.claude/worktrees/agent-acefedbd/native/macos/src-tauri/binaries/.gitkeep +0 -0
  710. package/.claude/worktrees/agent-acefedbd/native/macos/src-tauri/build.rs +3 -0
  711. package/.claude/worktrees/agent-acefedbd/native/macos/src-tauri/capabilities/default.json +26 -0
  712. package/.claude/worktrees/agent-acefedbd/native/macos/src-tauri/entitlements.plist +14 -0
  713. package/.claude/worktrees/agent-acefedbd/native/macos/src-tauri/icons/128x128.png +0 -0
  714. package/.claude/worktrees/agent-acefedbd/native/macos/src-tauri/icons/128x128@2x.png +0 -0
  715. package/.claude/worktrees/agent-acefedbd/native/macos/src-tauri/icons/32x32.png +0 -0
  716. package/.claude/worktrees/agent-acefedbd/native/macos/src-tauri/icons/icon.icns +0 -0
  717. package/.claude/worktrees/agent-acefedbd/native/macos/src-tauri/icons/tray-connected.png +0 -0
  718. package/.claude/worktrees/agent-acefedbd/native/macos/src-tauri/icons/tray-disconnected.png +0 -0
  719. package/.claude/worktrees/agent-acefedbd/native/macos/src-tauri/src/discovery.rs +221 -0
  720. package/.claude/worktrees/agent-acefedbd/native/macos/src-tauri/src/health.rs +67 -0
  721. package/.claude/worktrees/agent-acefedbd/native/macos/src-tauri/src/lib.rs +226 -0
  722. package/.claude/worktrees/agent-acefedbd/native/macos/src-tauri/src/main.rs +6 -0
  723. package/.claude/worktrees/agent-acefedbd/native/macos/src-tauri/src/notifications.rs +180 -0
  724. package/.claude/worktrees/agent-acefedbd/native/macos/src-tauri/src/server.rs +306 -0
  725. package/.claude/worktrees/agent-acefedbd/native/macos/src-tauri/tauri.conf.json +50 -0
  726. package/.claude/worktrees/agent-acefedbd/package.json +54 -0
  727. package/.claude/worktrees/agent-acefedbd/pkg.config.json +14 -0
  728. package/.claude/worktrees/agent-acefedbd/scripts/build-standalone.sh +106 -0
  729. package/.claude/worktrees/agent-acefedbd/scripts/cleanup.js +251 -0
  730. package/.claude/worktrees/agent-acefedbd/scripts/install-openclaw.js +986 -0
  731. package/.claude/worktrees/agent-acefedbd/scripts/install-skills.js +234 -0
  732. package/.claude/worktrees/agent-acefedbd/scripts/postinstall.js +224 -0
  733. package/.claude/worktrees/agent-acefedbd/scripts/preuninstall.js +68 -0
  734. package/.claude/worktrees/agent-acefedbd/scripts/run-e2e.sh +44 -0
  735. package/.claude/worktrees/agent-acefedbd/scripts/smoke-test-standalone.sh +101 -0
  736. package/.claude/worktrees/agent-acefedbd/scripts/sync-version.sh +28 -0
  737. package/.claude/worktrees/agent-acefedbd/scripts/verify-app-bundle.sh +34 -0
  738. package/.claude/worktrees/agent-acefedbd/src/dashboard/public/app.js +2649 -0
  739. package/.claude/worktrees/agent-acefedbd/src/dashboard/public/index.html +386 -0
  740. package/.claude/worktrees/agent-acefedbd/src/dashboard/public/onboarding.css +269 -0
  741. package/.claude/worktrees/agent-acefedbd/src/dashboard/public/onboarding.html +96 -0
  742. package/.claude/worktrees/agent-acefedbd/src/dashboard/public/onboarding.js +277 -0
  743. package/.claude/worktrees/agent-acefedbd/src/dashboard/public/style.css +1274 -0
  744. package/.claude/worktrees/agent-acefedbd/src/index.js +76 -0
  745. package/.claude/worktrees/agent-acefedbd/src/lib/agent-card.js +111 -0
  746. package/.claude/worktrees/agent-acefedbd/src/lib/call-monitor.js +205 -0
  747. package/.claude/worktrees/agent-acefedbd/src/lib/callbook.js +366 -0
  748. package/.claude/worktrees/agent-acefedbd/src/lib/claude-subagent.js +696 -0
  749. package/.claude/worktrees/agent-acefedbd/src/lib/client.js +683 -0
  750. package/.claude/worktrees/agent-acefedbd/src/lib/config.js +480 -0
  751. package/.claude/worktrees/agent-acefedbd/src/lib/conversation-driver.js +608 -0
  752. package/.claude/worktrees/agent-acefedbd/src/lib/conversations.js +830 -0
  753. package/.claude/worktrees/agent-acefedbd/src/lib/crypto.js +113 -0
  754. package/.claude/worktrees/agent-acefedbd/src/lib/dashboard-events.js +213 -0
  755. package/.claude/worktrees/agent-acefedbd/src/lib/disclosure.js +792 -0
  756. package/.claude/worktrees/agent-acefedbd/src/lib/external-ip.js +211 -0
  757. package/.claude/worktrees/agent-acefedbd/src/lib/invite-host.js +223 -0
  758. package/.claude/worktrees/agent-acefedbd/src/lib/local-request.js +69 -0
  759. package/.claude/worktrees/agent-acefedbd/src/lib/logger.js +677 -0
  760. package/.claude/worktrees/agent-acefedbd/src/lib/openclaw-integration.js +339 -0
  761. package/.claude/worktrees/agent-acefedbd/src/lib/pid-file.js +103 -0
  762. package/.claude/worktrees/agent-acefedbd/src/lib/port-scanner.js +83 -0
  763. package/.claude/worktrees/agent-acefedbd/src/lib/prompt-template.js +355 -0
  764. package/.claude/worktrees/agent-acefedbd/src/lib/runtime-adapter.js +701 -0
  765. package/.claude/worktrees/agent-acefedbd/src/lib/summarizer.js +156 -0
  766. package/.claude/worktrees/agent-acefedbd/src/lib/summary-formatter.js +168 -0
  767. package/.claude/worktrees/agent-acefedbd/src/lib/summary-prompt.js +203 -0
  768. package/.claude/worktrees/agent-acefedbd/src/lib/tokens.js +868 -0
  769. package/.claude/worktrees/agent-acefedbd/src/lib/turn-timeout.js +52 -0
  770. package/.claude/worktrees/agent-acefedbd/src/lib/update-checker.js +93 -0
  771. package/.claude/worktrees/agent-acefedbd/src/lib/update-manager.js +313 -0
  772. package/.claude/worktrees/agent-acefedbd/src/routes/a2a.js +1213 -0
  773. package/.claude/worktrees/agent-acefedbd/src/routes/callbook.js +142 -0
  774. package/.claude/worktrees/agent-acefedbd/src/routes/dashboard.js +1688 -0
  775. package/.claude/worktrees/agent-acefedbd/src/server.js +1179 -0
  776. package/.claude/worktrees/agent-ad420869/.a2a-manifest.json +70 -0
  777. package/.claude/worktrees/agent-ad420869/.c8rc.json +16 -0
  778. package/.claude/worktrees/agent-ad420869/.claude/a2a-skill-reference.md +462 -0
  779. package/.claude/worktrees/agent-ad420869/.claude/commands/a2a-app.md +42 -0
  780. package/.claude/worktrees/agent-ad420869/.claude/commands/a2a-call.md +26 -0
  781. package/.claude/worktrees/agent-ad420869/.claude/commands/a2a-contacts.md +31 -0
  782. package/.claude/worktrees/agent-ad420869/.claude/commands/a2a-conversations.md +47 -0
  783. package/.claude/worktrees/agent-ad420869/.claude/commands/a2a-gui.md +30 -0
  784. package/.claude/worktrees/agent-ad420869/.claude/commands/a2a-invite.md +63 -0
  785. package/.claude/worktrees/agent-ad420869/.claude/commands/a2a-setup.md +30 -0
  786. package/.claude/worktrees/agent-ad420869/.claude/commands/a2a-skills.md +27 -0
  787. package/.claude/worktrees/agent-ad420869/.claude/commands/a2a-status.md +46 -0
  788. package/.claude/worktrees/agent-ad420869/.claude/commands/a2a-uninstall.md +36 -0
  789. package/.claude/worktrees/agent-ad420869/.claude/commands/a2a-update.md +41 -0
  790. package/.claude/worktrees/agent-ad420869/.node-version +1 -0
  791. package/.claude/worktrees/agent-ad420869/ARCHITECTURE.md +135 -0
  792. package/.claude/worktrees/agent-ad420869/CLAUDE-INSTALL.md +156 -0
  793. package/.claude/worktrees/agent-ad420869/CONVENTIONS.md +178 -0
  794. package/.claude/worktrees/agent-ad420869/README.md +470 -0
  795. package/.claude/worktrees/agent-ad420869/SKILL.md +462 -0
  796. package/.claude/worktrees/agent-ad420869/bin/cli.js +3184 -0
  797. package/.claude/worktrees/agent-ad420869/biome.json +27 -0
  798. package/.claude/worktrees/agent-ad420869/docs/assessments/2026-02-27-google-a2a-protocol-assessment.md +292 -0
  799. package/.claude/worktrees/agent-ad420869/docs/plans/2026-02-15-port-fallback-warning-design.md +611 -0
  800. package/.claude/worktrees/agent-ad420869/docs/plans/2026-02-16-a2a-callbook-macos-app.md +1660 -0
  801. package/.claude/worktrees/agent-ad420869/docs/plans/2026-02-16-auto-updater.md +1284 -0
  802. package/.claude/worktrees/agent-ad420869/docs/plans/2026-02-16-bugfixes-22-24.md +246 -0
  803. package/.claude/worktrees/agent-ad420869/docs/plans/2026-02-16-e2e-test-prompt-sequence.md +3085 -0
  804. package/.claude/worktrees/agent-ad420869/docs/plans/2026-02-16-orphan-process-fix.md +962 -0
  805. package/.claude/worktrees/agent-ad420869/docs/plans/2026-02-17-claude-code-codex-skills.md +770 -0
  806. package/.claude/worktrees/agent-ad420869/docs/plans/2026-03-01-a2a-68-openclaw-integration-tests.md +676 -0
  807. package/.claude/worktrees/agent-ad420869/docs/plans/2026-03-01-a2a-77-invoke-security-tests.md +661 -0
  808. package/.claude/worktrees/agent-ad420869/docs/prompts/e2e-test-agent.md +368 -0
  809. package/.claude/worktrees/agent-ad420869/docs/protocol.md +440 -0
  810. package/.claude/worktrees/agent-ad420869/docs/signing-setup.md +49 -0
  811. package/.claude/worktrees/agent-ad420869/eslint.config.js +16 -0
  812. package/.claude/worktrees/agent-ad420869/knip.json +17 -0
  813. package/.claude/worktrees/agent-ad420869/native/macos/index.html +182 -0
  814. package/.claude/worktrees/agent-ad420869/native/macos/package.json +8 -0
  815. package/.claude/worktrees/agent-ad420869/native/macos/src-tauri/Cargo.lock +5875 -0
  816. package/.claude/worktrees/agent-ad420869/native/macos/src-tauri/Cargo.toml +24 -0
  817. package/.claude/worktrees/agent-ad420869/native/macos/src-tauri/binaries/.gitkeep +0 -0
  818. package/.claude/worktrees/agent-ad420869/native/macos/src-tauri/build.rs +3 -0
  819. package/.claude/worktrees/agent-ad420869/native/macos/src-tauri/capabilities/default.json +26 -0
  820. package/.claude/worktrees/agent-ad420869/native/macos/src-tauri/entitlements.plist +14 -0
  821. package/.claude/worktrees/agent-ad420869/native/macos/src-tauri/icons/128x128.png +0 -0
  822. package/.claude/worktrees/agent-ad420869/native/macos/src-tauri/icons/128x128@2x.png +0 -0
  823. package/.claude/worktrees/agent-ad420869/native/macos/src-tauri/icons/32x32.png +0 -0
  824. package/.claude/worktrees/agent-ad420869/native/macos/src-tauri/icons/icon.icns +0 -0
  825. package/.claude/worktrees/agent-ad420869/native/macos/src-tauri/icons/tray-connected.png +0 -0
  826. package/.claude/worktrees/agent-ad420869/native/macos/src-tauri/icons/tray-disconnected.png +0 -0
  827. package/.claude/worktrees/agent-ad420869/native/macos/src-tauri/src/discovery.rs +221 -0
  828. package/.claude/worktrees/agent-ad420869/native/macos/src-tauri/src/health.rs +67 -0
  829. package/.claude/worktrees/agent-ad420869/native/macos/src-tauri/src/lib.rs +226 -0
  830. package/.claude/worktrees/agent-ad420869/native/macos/src-tauri/src/main.rs +6 -0
  831. package/.claude/worktrees/agent-ad420869/native/macos/src-tauri/src/notifications.rs +180 -0
  832. package/.claude/worktrees/agent-ad420869/native/macos/src-tauri/src/server.rs +306 -0
  833. package/.claude/worktrees/agent-ad420869/native/macos/src-tauri/tauri.conf.json +50 -0
  834. package/.claude/worktrees/agent-ad420869/package.json +54 -0
  835. package/.claude/worktrees/agent-ad420869/pkg.config.json +14 -0
  836. package/.claude/worktrees/agent-ad420869/scripts/build-standalone.sh +106 -0
  837. package/.claude/worktrees/agent-ad420869/scripts/cleanup.js +251 -0
  838. package/.claude/worktrees/agent-ad420869/scripts/install-openclaw.js +986 -0
  839. package/.claude/worktrees/agent-ad420869/scripts/install-skills.js +234 -0
  840. package/.claude/worktrees/agent-ad420869/scripts/postinstall.js +224 -0
  841. package/.claude/worktrees/agent-ad420869/scripts/preuninstall.js +68 -0
  842. package/.claude/worktrees/agent-ad420869/scripts/run-e2e.sh +44 -0
  843. package/.claude/worktrees/agent-ad420869/scripts/smoke-test-standalone.sh +101 -0
  844. package/.claude/worktrees/agent-ad420869/scripts/sync-version.sh +28 -0
  845. package/.claude/worktrees/agent-ad420869/scripts/verify-app-bundle.sh +34 -0
  846. package/.claude/worktrees/agent-ad420869/src/dashboard/public/app.js +2683 -0
  847. package/.claude/worktrees/agent-ad420869/src/dashboard/public/index.html +394 -0
  848. package/.claude/worktrees/agent-ad420869/src/dashboard/public/onboarding.css +269 -0
  849. package/.claude/worktrees/agent-ad420869/src/dashboard/public/onboarding.html +96 -0
  850. package/.claude/worktrees/agent-ad420869/src/dashboard/public/onboarding.js +277 -0
  851. package/.claude/worktrees/agent-ad420869/src/dashboard/public/style.css +1294 -0
  852. package/.claude/worktrees/agent-ad420869/src/index.js +76 -0
  853. package/.claude/worktrees/agent-ad420869/src/lib/agent-card.js +111 -0
  854. package/.claude/worktrees/agent-ad420869/src/lib/call-monitor.js +205 -0
  855. package/.claude/worktrees/agent-ad420869/src/lib/callbook.js +366 -0
  856. package/.claude/worktrees/agent-ad420869/src/lib/claude-subagent.js +696 -0
  857. package/.claude/worktrees/agent-ad420869/src/lib/client.js +683 -0
  858. package/.claude/worktrees/agent-ad420869/src/lib/config.js +480 -0
  859. package/.claude/worktrees/agent-ad420869/src/lib/conversation-driver.js +608 -0
  860. package/.claude/worktrees/agent-ad420869/src/lib/conversations.js +830 -0
  861. package/.claude/worktrees/agent-ad420869/src/lib/crypto.js +113 -0
  862. package/.claude/worktrees/agent-ad420869/src/lib/dashboard-events.js +213 -0
  863. package/.claude/worktrees/agent-ad420869/src/lib/disclosure.js +792 -0
  864. package/.claude/worktrees/agent-ad420869/src/lib/external-ip.js +211 -0
  865. package/.claude/worktrees/agent-ad420869/src/lib/invite-host.js +223 -0
  866. package/.claude/worktrees/agent-ad420869/src/lib/local-request.js +69 -0
  867. package/.claude/worktrees/agent-ad420869/src/lib/logger.js +677 -0
  868. package/.claude/worktrees/agent-ad420869/src/lib/openclaw-integration.js +339 -0
  869. package/.claude/worktrees/agent-ad420869/src/lib/pid-file.js +103 -0
  870. package/.claude/worktrees/agent-ad420869/src/lib/port-scanner.js +83 -0
  871. package/.claude/worktrees/agent-ad420869/src/lib/prompt-template.js +355 -0
  872. package/.claude/worktrees/agent-ad420869/src/lib/runtime-adapter.js +701 -0
  873. package/.claude/worktrees/agent-ad420869/src/lib/summarizer.js +156 -0
  874. package/.claude/worktrees/agent-ad420869/src/lib/summary-formatter.js +168 -0
  875. package/.claude/worktrees/agent-ad420869/src/lib/summary-prompt.js +203 -0
  876. package/.claude/worktrees/agent-ad420869/src/lib/tokens.js +868 -0
  877. package/.claude/worktrees/agent-ad420869/src/lib/turn-timeout.js +52 -0
  878. package/.claude/worktrees/agent-ad420869/src/lib/update-checker.js +93 -0
  879. package/.claude/worktrees/agent-ad420869/src/lib/update-manager.js +313 -0
  880. package/.claude/worktrees/agent-ad420869/src/routes/a2a.js +1213 -0
  881. package/.claude/worktrees/agent-ad420869/src/routes/callbook.js +142 -0
  882. package/.claude/worktrees/agent-ad420869/src/routes/dashboard.js +1688 -0
  883. package/.claude/worktrees/agent-ad420869/src/server.js +1179 -0
  884. package/.claude/worktrees/agent-af1f3b59/.c8rc.json +16 -0
  885. package/.claude/worktrees/agent-af1f3b59/.claude/commands/a2a-app.md +42 -0
  886. package/.claude/worktrees/agent-af1f3b59/.claude/commands/a2a-call.md +26 -0
  887. package/.claude/worktrees/agent-af1f3b59/.claude/commands/a2a-contacts.md +31 -0
  888. package/.claude/worktrees/agent-af1f3b59/.claude/commands/a2a-conversations.md +47 -0
  889. package/.claude/worktrees/agent-af1f3b59/.claude/commands/a2a-gui.md +30 -0
  890. package/.claude/worktrees/agent-af1f3b59/.claude/commands/a2a-invite.md +63 -0
  891. package/.claude/worktrees/agent-af1f3b59/.claude/commands/a2a-setup.md +30 -0
  892. package/.claude/worktrees/agent-af1f3b59/.claude/commands/a2a-skills.md +27 -0
  893. package/.claude/worktrees/agent-af1f3b59/.claude/commands/a2a-status.md +46 -0
  894. package/.claude/worktrees/agent-af1f3b59/.claude/commands/a2a-uninstall.md +36 -0
  895. package/.claude/worktrees/agent-af1f3b59/.claude/commands/a2a-update.md +41 -0
  896. package/.claude/worktrees/agent-af1f3b59/.node-version +1 -0
  897. package/.claude/worktrees/agent-af1f3b59/ARCHITECTURE.md +135 -0
  898. package/.claude/worktrees/agent-af1f3b59/CLAUDE-INSTALL.md +156 -0
  899. package/.claude/worktrees/agent-af1f3b59/CONVENTIONS.md +178 -0
  900. package/.claude/worktrees/agent-af1f3b59/README.md +470 -0
  901. package/.claude/worktrees/agent-af1f3b59/SKILL.md +462 -0
  902. package/.claude/worktrees/agent-af1f3b59/bin/cli.js +3184 -0
  903. package/.claude/worktrees/agent-af1f3b59/biome.json +27 -0
  904. package/.claude/worktrees/agent-af1f3b59/docs/assessments/2026-02-27-google-a2a-protocol-assessment.md +292 -0
  905. package/.claude/worktrees/agent-af1f3b59/docs/plans/2026-02-15-port-fallback-warning-design.md +611 -0
  906. package/.claude/worktrees/agent-af1f3b59/docs/plans/2026-02-16-a2a-callbook-macos-app.md +1660 -0
  907. package/.claude/worktrees/agent-af1f3b59/docs/plans/2026-02-16-auto-updater.md +1284 -0
  908. package/.claude/worktrees/agent-af1f3b59/docs/plans/2026-02-16-bugfixes-22-24.md +246 -0
  909. package/.claude/worktrees/agent-af1f3b59/docs/plans/2026-02-16-e2e-test-prompt-sequence.md +3085 -0
  910. package/.claude/worktrees/agent-af1f3b59/docs/plans/2026-02-16-orphan-process-fix.md +962 -0
  911. package/.claude/worktrees/agent-af1f3b59/docs/plans/2026-02-17-claude-code-codex-skills.md +770 -0
  912. package/.claude/worktrees/agent-af1f3b59/docs/plans/2026-03-01-a2a-68-openclaw-integration-tests.md +676 -0
  913. package/.claude/worktrees/agent-af1f3b59/docs/plans/2026-03-01-a2a-77-invoke-security-tests.md +661 -0
  914. package/.claude/worktrees/agent-af1f3b59/docs/prompts/e2e-test-agent.md +368 -0
  915. package/.claude/worktrees/agent-af1f3b59/docs/protocol.md +440 -0
  916. package/.claude/worktrees/agent-af1f3b59/docs/signing-setup.md +49 -0
  917. package/.claude/worktrees/agent-af1f3b59/eslint.config.js +16 -0
  918. package/.claude/worktrees/agent-af1f3b59/knip.json +17 -0
  919. package/.claude/worktrees/agent-af1f3b59/native/macos/index.html +179 -0
  920. package/.claude/worktrees/agent-af1f3b59/native/macos/package.json +8 -0
  921. package/.claude/worktrees/agent-af1f3b59/native/macos/src-tauri/Cargo.lock +5875 -0
  922. package/.claude/worktrees/agent-af1f3b59/native/macos/src-tauri/Cargo.toml +24 -0
  923. package/.claude/worktrees/agent-af1f3b59/native/macos/src-tauri/binaries/.gitkeep +0 -0
  924. package/.claude/worktrees/agent-af1f3b59/native/macos/src-tauri/build.rs +3 -0
  925. package/.claude/worktrees/agent-af1f3b59/native/macos/src-tauri/capabilities/default.json +26 -0
  926. package/.claude/worktrees/agent-af1f3b59/native/macos/src-tauri/dmg-background.png +0 -0
  927. package/.claude/worktrees/agent-af1f3b59/native/macos/src-tauri/dmg-background@2x.png +0 -0
  928. package/.claude/worktrees/agent-af1f3b59/native/macos/src-tauri/entitlements.plist +14 -0
  929. package/.claude/worktrees/agent-af1f3b59/native/macos/src-tauri/icons/128x128.png +0 -0
  930. package/.claude/worktrees/agent-af1f3b59/native/macos/src-tauri/icons/128x128@2x.png +0 -0
  931. package/.claude/worktrees/agent-af1f3b59/native/macos/src-tauri/icons/256x256.png +0 -0
  932. package/.claude/worktrees/agent-af1f3b59/native/macos/src-tauri/icons/32x32.png +0 -0
  933. package/.claude/worktrees/agent-af1f3b59/native/macos/src-tauri/icons/512x512.png +0 -0
  934. package/.claude/worktrees/agent-af1f3b59/native/macos/src-tauri/icons/512x512@2x.png +0 -0
  935. package/.claude/worktrees/agent-af1f3b59/native/macos/src-tauri/icons/icon.icns +0 -0
  936. package/.claude/worktrees/agent-af1f3b59/native/macos/src-tauri/icons/tray-connected.png +0 -0
  937. package/.claude/worktrees/agent-af1f3b59/native/macos/src-tauri/icons/tray-disconnected.png +0 -0
  938. package/.claude/worktrees/agent-af1f3b59/native/macos/src-tauri/src/discovery.rs +184 -0
  939. package/.claude/worktrees/agent-af1f3b59/native/macos/src-tauri/src/health.rs +67 -0
  940. package/.claude/worktrees/agent-af1f3b59/native/macos/src-tauri/src/lib.rs +226 -0
  941. package/.claude/worktrees/agent-af1f3b59/native/macos/src-tauri/src/main.rs +6 -0
  942. package/.claude/worktrees/agent-af1f3b59/native/macos/src-tauri/src/notifications.rs +180 -0
  943. package/.claude/worktrees/agent-af1f3b59/native/macos/src-tauri/src/server.rs +306 -0
  944. package/.claude/worktrees/agent-af1f3b59/native/macos/src-tauri/tauri.conf.json +60 -0
  945. package/.claude/worktrees/agent-af1f3b59/native/macos/src-tauri/volume-icon.icns +0 -0
  946. package/.claude/worktrees/agent-af1f3b59/package.json +54 -0
  947. package/.claude/worktrees/agent-af1f3b59/pkg.config.json +14 -0
  948. package/.claude/worktrees/agent-af1f3b59/scripts/build-standalone.sh +106 -0
  949. package/.claude/worktrees/agent-af1f3b59/scripts/cleanup.js +251 -0
  950. package/.claude/worktrees/agent-af1f3b59/scripts/install-openclaw.js +986 -0
  951. package/.claude/worktrees/agent-af1f3b59/scripts/install-skills.js +234 -0
  952. package/.claude/worktrees/agent-af1f3b59/scripts/postinstall.js +224 -0
  953. package/.claude/worktrees/agent-af1f3b59/scripts/preuninstall.js +68 -0
  954. package/.claude/worktrees/agent-af1f3b59/scripts/run-e2e.sh +44 -0
  955. package/.claude/worktrees/agent-af1f3b59/scripts/smoke-test-standalone.sh +101 -0
  956. package/.claude/worktrees/agent-af1f3b59/scripts/sync-version.sh +28 -0
  957. package/.claude/worktrees/agent-af1f3b59/scripts/verify-app-bundle.sh +34 -0
  958. package/.claude/worktrees/agent-af1f3b59/src/dashboard/public/app.js +2649 -0
  959. package/.claude/worktrees/agent-af1f3b59/src/dashboard/public/index.html +386 -0
  960. package/.claude/worktrees/agent-af1f3b59/src/dashboard/public/style.css +1274 -0
  961. package/.claude/worktrees/agent-af1f3b59/src/index.js +76 -0
  962. package/.claude/worktrees/agent-af1f3b59/src/lib/agent-card.js +111 -0
  963. package/.claude/worktrees/agent-af1f3b59/src/lib/call-monitor.js +205 -0
  964. package/.claude/worktrees/agent-af1f3b59/src/lib/callbook.js +366 -0
  965. package/.claude/worktrees/agent-af1f3b59/src/lib/claude-subagent.js +696 -0
  966. package/.claude/worktrees/agent-af1f3b59/src/lib/client.js +683 -0
  967. package/.claude/worktrees/agent-af1f3b59/src/lib/config.js +480 -0
  968. package/.claude/worktrees/agent-af1f3b59/src/lib/conversation-driver.js +608 -0
  969. package/.claude/worktrees/agent-af1f3b59/src/lib/conversations.js +830 -0
  970. package/.claude/worktrees/agent-af1f3b59/src/lib/crypto.js +113 -0
  971. package/.claude/worktrees/agent-af1f3b59/src/lib/dashboard-events.js +213 -0
  972. package/.claude/worktrees/agent-af1f3b59/src/lib/disclosure.js +792 -0
  973. package/.claude/worktrees/agent-af1f3b59/src/lib/external-ip.js +211 -0
  974. package/.claude/worktrees/agent-af1f3b59/src/lib/invite-host.js +223 -0
  975. package/.claude/worktrees/agent-af1f3b59/src/lib/local-request.js +69 -0
  976. package/.claude/worktrees/agent-af1f3b59/src/lib/logger.js +677 -0
  977. package/.claude/worktrees/agent-af1f3b59/src/lib/openclaw-integration.js +339 -0
  978. package/.claude/worktrees/agent-af1f3b59/src/lib/pid-file.js +103 -0
  979. package/.claude/worktrees/agent-af1f3b59/src/lib/port-scanner.js +83 -0
  980. package/.claude/worktrees/agent-af1f3b59/src/lib/prompt-template.js +355 -0
  981. package/.claude/worktrees/agent-af1f3b59/src/lib/runtime-adapter.js +701 -0
  982. package/.claude/worktrees/agent-af1f3b59/src/lib/summarizer.js +156 -0
  983. package/.claude/worktrees/agent-af1f3b59/src/lib/summary-formatter.js +168 -0
  984. package/.claude/worktrees/agent-af1f3b59/src/lib/summary-prompt.js +203 -0
  985. package/.claude/worktrees/agent-af1f3b59/src/lib/tokens.js +868 -0
  986. package/.claude/worktrees/agent-af1f3b59/src/lib/turn-timeout.js +52 -0
  987. package/.claude/worktrees/agent-af1f3b59/src/lib/update-checker.js +93 -0
  988. package/.claude/worktrees/agent-af1f3b59/src/lib/update-manager.js +313 -0
  989. package/.claude/worktrees/agent-af1f3b59/src/routes/a2a.js +1213 -0
  990. package/.claude/worktrees/agent-af1f3b59/src/routes/callbook.js +142 -0
  991. package/.claude/worktrees/agent-af1f3b59/src/routes/dashboard.js +1578 -0
  992. package/.claude/worktrees/agent-af1f3b59/src/server.js +1179 -0
  993. package/CONVENTIONS.md +39 -0
  994. package/docs/app.js +30 -0
  995. package/docs/assets/icon-32.png +0 -0
  996. package/docs/assets/icon-64.png +0 -0
  997. package/docs/index.html +117 -0
  998. package/docs/plans/2026-03-06-a2a-100-tauri-auto-updater.md +519 -0
  999. package/docs/plans/2026-03-06-a2a-101-dmg-installer-polish.md +229 -0
  1000. package/docs/plans/2026-03-06-a2a-102-landing-page.md +611 -0
  1001. package/docs/plans/2026-03-06-a2a-103-standalone-e2e-tests.md +810 -0
  1002. package/docs/plans/2026-03-06-a2a-99-native-onboarding-wizard.md +1261 -0
  1003. package/docs/style.css +209 -0
  1004. package/native/macos/index.html +7 -4
  1005. package/native/macos/src-tauri/Cargo.toml +1 -0
  1006. package/native/macos/src-tauri/dmg-background.png +0 -0
  1007. package/native/macos/src-tauri/dmg-background@2x.png +0 -0
  1008. package/native/macos/src-tauri/icons/256x256.png +0 -0
  1009. package/native/macos/src-tauri/icons/512x512.png +0 -0
  1010. package/native/macos/src-tauri/icons/512x512@2x.png +0 -0
  1011. package/native/macos/src-tauri/src/discovery.rs +37 -0
  1012. package/native/macos/src-tauri/src/lib.rs +32 -2
  1013. package/native/macos/src-tauri/src/updater.rs +124 -0
  1014. package/native/macos/src-tauri/tauri.conf.json +21 -3
  1015. package/native/macos/src-tauri/volume-icon.icns +0 -0
  1016. package/package.json +2 -1
  1017. package/scripts/generate-update-manifest.sh +42 -0
  1018. package/scripts/run-e2e.sh +8 -0
  1019. package/src/dashboard/public/app.js +34 -0
  1020. package/src/dashboard/public/index.html +7 -0
  1021. package/src/dashboard/public/onboarding.css +269 -0
  1022. package/src/dashboard/public/onboarding.html +96 -0
  1023. package/src/dashboard/public/onboarding.js +277 -0
  1024. package/src/dashboard/public/style.css +20 -0
  1025. package/src/routes/dashboard.js +110 -0
@@ -0,0 +1,3184 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * A2A Calling CLI
4
+ *
5
+ * Usage:
6
+ * a2a create [options] Create an A2A token
7
+ * a2a list List active tokens
8
+ * a2a revoke <id> Revoke a token
9
+ * a2a add <url> [name] Add a contact (alias of "contacts add")
10
+ * a2a remotes List contacts (alias of "contacts")
11
+ * a2a call <url> <msg> Call a contact (or invite URL)
12
+ * a2a ping <url> Ping an invite URL
13
+ * a2a gui Open the local dashboard GUI in a browser
14
+ * a2a app <action> Manage native macOS app (status/install/uninstall)
15
+ * a2a setup Auto setup (gateway-aware dashboard install)
16
+ * a2a uninstall Stop server and remove local A2A config
17
+ */
18
+
19
+ const fs = require('fs');
20
+ const os = require('os');
21
+ const path = require('path');
22
+ const crypto = require('crypto');
23
+ const { spawn } = require('child_process');
24
+ const { TokenStore } = require('../src/lib/tokens');
25
+ const { A2AClient } = require('../src/lib/client');
26
+
27
+ const CONFIG_DIR = process.env.A2A_CONFIG_DIR || process.env.OPENCLAW_CONFIG_DIR || path.join(os.homedir(), '.config', 'openclaw');
28
+ const CONFIG_PATH = path.join(CONFIG_DIR, 'a2a-config.json');
29
+ const ONBOARDING_EXEMPT = new Set([
30
+ 'quickstart',
31
+ 'help',
32
+ 'version',
33
+ 'status',
34
+ 'update',
35
+ 'uninstall',
36
+ 'onboard',
37
+ 'gui',
38
+ 'dashboard',
39
+ 'server',
40
+ 'setup',
41
+ 'app',
42
+ 'install',
43
+ 'skills'
44
+ ]);
45
+
46
+ function isOnboarded() {
47
+ try {
48
+ const config = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8'));
49
+ return config.onboarding?.version === 2 && config.onboarding?.step === 'complete';
50
+ } catch (err) {
51
+ return false;
52
+ }
53
+ }
54
+
55
+ // Lazy load conversation store (requires better-sqlite3)
56
+ let convStore = null;
57
+ function getConvStore() {
58
+ if (convStore === false) return null; // Already tried and failed
59
+ if (!convStore) {
60
+ try {
61
+ const { ConversationStore } = require('../src/lib/conversations');
62
+ convStore = new ConversationStore();
63
+ if (!convStore.isAvailable()) {
64
+ console.error(`[a2a] ${convStore.getError()}`);
65
+ convStore = false;
66
+ return null;
67
+ }
68
+ } catch (err) {
69
+ convStore = false;
70
+ return null;
71
+ }
72
+ }
73
+ return convStore;
74
+ }
75
+
76
+ const store = new TokenStore();
77
+
78
+ // Commands that should hard-fail with a clear error when not onboarded,
79
+ // rather than falling through to the interactive quickstart flow.
80
+ // These are outbound operations often invoked by agents/automation.
81
+ const ONBOARDING_HARD_FAIL = new Set([
82
+ 'call', 'ping'
83
+ ]);
84
+
85
+ // ── enforceOnboarding ────────────────────────────────────────────────────
86
+ // If onboarding is incomplete or the config is missing/invalid, run the
87
+ // full quickstart flow inline — verbose, with direct stdio. The agent sees
88
+ // the banner, port selection, server start, and disclosure prompt right here.
89
+ //
90
+ // This is the primary onboarding entry point for agents. npm postinstall
91
+ // silently starts the server (npm captures its output), so the first time
92
+ // the agent runs ANY `a2a` command, this function fires and gives the agent
93
+ // the full verbose walkthrough it needs to complete setup.
94
+ //
95
+ // Returns a Promise if quickstart needs to run (caller must await), or
96
+ // undefined if onboarding is already complete.
97
+ function enforceOnboarding(command) {
98
+ if (ONBOARDING_EXEMPT.has(command)) {
99
+ return;
100
+ }
101
+
102
+ if (!isOnboarded()) {
103
+ // For outbound commands (call, ping, status), fail immediately with
104
+ // a clear error instead of dumping onboarding prompts. This prevents
105
+ // calling agents from receiving walls of setup instructions.
106
+ if (ONBOARDING_HARD_FAIL.has(command)) {
107
+ console.error('❌ Onboarding not complete. Run `a2a quickstart` first to set up your agent.');
108
+ process.exit(1);
109
+ }
110
+
111
+ // Run the full quickstart flow inline — verbose output, direct stdio.
112
+ // This replaces the original command; after onboarding the agent can
113
+ // re-run their intended command.
114
+ return commands.quickstart({ flags: {}, positional: [] });
115
+ }
116
+ }
117
+
118
+ // Format relative time
119
+ function formatTimeAgo(date) {
120
+ const seconds = Math.floor((new Date() - date) / 1000);
121
+ if (seconds < 60) return 'just now';
122
+ const minutes = Math.floor(seconds / 60);
123
+ if (minutes < 60) return `${minutes}m ago`;
124
+ const hours = Math.floor(minutes / 60);
125
+ if (hours < 24) return `${hours}h ago`;
126
+ const days = Math.floor(hours / 24);
127
+ if (days < 7) return `${days}d ago`;
128
+ return date.toLocaleDateString();
129
+ }
130
+
131
+ function openInBrowser(url) {
132
+ const platform = process.platform;
133
+ let cmd = null;
134
+ let args = [];
135
+
136
+ if (platform === 'darwin') {
137
+ cmd = 'open';
138
+ args = [url];
139
+ } else if (platform === 'win32') {
140
+ cmd = 'cmd';
141
+ args = ['/c', 'start', '', url];
142
+ } else {
143
+ cmd = 'xdg-open';
144
+ args = [url];
145
+ }
146
+
147
+ try {
148
+ const child = spawn(cmd, args, { stdio: 'ignore', detached: true });
149
+ child.unref();
150
+ return { attempted: true, command: [cmd, ...args].join(' ') };
151
+ } catch (err) {
152
+ return { attempted: false, error: err.message };
153
+ }
154
+ }
155
+
156
+ function findNativeApp() {
157
+ if (os.platform() !== 'darwin') return null;
158
+
159
+ const candidates = [
160
+ path.join(os.homedir(), 'Applications', 'A2A Callbook.app'),
161
+ '/Applications/A2A Callbook.app',
162
+ ];
163
+
164
+ for (const appPath of candidates) {
165
+ try {
166
+ if (fs.existsSync(appPath)) return appPath;
167
+ } catch (_) {}
168
+ }
169
+
170
+ return null;
171
+ }
172
+
173
+ function getNativeAppPaths() {
174
+ return {
175
+ appDir: path.join(os.homedir(), 'Applications'),
176
+ appPath: path.join(os.homedir(), 'Applications', 'A2A Callbook.app')
177
+ };
178
+ }
179
+
180
+ function parseInstalledNativeAppVersion(appPath) {
181
+ if (!appPath) return null;
182
+ const plistPath = path.join(appPath, 'Contents', 'Info.plist');
183
+ if (!fs.existsSync(plistPath)) return null;
184
+ try {
185
+ const plist = fs.readFileSync(plistPath, 'utf8');
186
+ const m = plist.match(/<key>CFBundleShortVersionString<\/key>\s*<string>([^<]+)<\/string>/);
187
+ return m && m[1] ? m[1].trim() : null;
188
+ } catch (_) {
189
+ return null;
190
+ }
191
+ }
192
+
193
+ function installNativeMacApp(options = {}) {
194
+ if (os.platform() !== 'darwin') {
195
+ return { success: false, skipped: 'not_macos' };
196
+ }
197
+ const quiet = Boolean(options.quiet);
198
+ const force = Boolean(options.force);
199
+ const version = require('../package.json').version;
200
+ const { appDir, appPath } = getNativeAppPaths();
201
+ const installedVersion = parseInstalledNativeAppVersion(appPath);
202
+ if (!force && installedVersion === version) {
203
+ return { success: true, installed: false, version, appPath, reason: 'already_current' };
204
+ }
205
+
206
+ const tarUrl = `https://github.com/onthegonow/a2a_calling/releases/download/v${version}/A2A-Callbook-${version}.app.tar.gz`;
207
+ const tmpFile = path.join(os.tmpdir(), `a2a-callbook-${version}.app.tar.gz`);
208
+ const { execFileSync } = require('child_process');
209
+
210
+ try {
211
+ fs.mkdirSync(appDir, { recursive: true });
212
+ execFileSync('curl', ['-fL', '-o', tmpFile, tarUrl], { timeout: 120000, stdio: quiet ? 'ignore' : 'inherit' });
213
+ if (!fs.existsSync(tmpFile) || fs.statSync(tmpFile).size < 1000) {
214
+ return { success: false, error: 'download_failed' };
215
+ }
216
+ if (fs.existsSync(appPath)) {
217
+ fs.rmSync(appPath, { recursive: true, force: true });
218
+ }
219
+ execFileSync('tar', ['-xzf', tmpFile, '-C', appDir], { timeout: 60000, stdio: quiet ? 'ignore' : 'inherit' });
220
+ try { fs.unlinkSync(tmpFile); } catch (_) {}
221
+ return { success: true, installed: true, version, appPath };
222
+ } catch (err) {
223
+ try { fs.unlinkSync(tmpFile); } catch (_) {}
224
+ return { success: false, error: err.message || 'install_failed' };
225
+ }
226
+ }
227
+
228
+ function uninstallNativeMacApp() {
229
+ if (os.platform() !== 'darwin') {
230
+ return { success: false, skipped: 'not_macos' };
231
+ }
232
+ const candidates = [
233
+ path.join(os.homedir(), 'Applications', 'A2A Callbook.app'),
234
+ '/Applications/A2A Callbook.app'
235
+ ];
236
+ const existing = candidates.filter((candidate) => {
237
+ try {
238
+ return fs.existsSync(candidate);
239
+ } catch (_) {
240
+ return false;
241
+ }
242
+ });
243
+ if (existing.length === 0) {
244
+ return { success: true, removed: false, appPath: candidates[0] };
245
+ }
246
+
247
+ const removed = [];
248
+ const failed = [];
249
+ for (const appPath of existing) {
250
+ try {
251
+ fs.rmSync(appPath, { recursive: true, force: true });
252
+ removed.push(appPath);
253
+ } catch (err) {
254
+ failed.push({ appPath, error: err && err.message ? err.message : 'uninstall_failed' });
255
+ }
256
+ }
257
+ if (failed.length > 0) {
258
+ return {
259
+ success: false,
260
+ error: failed.map((f) => `${f.appPath}: ${f.error}`).join('; '),
261
+ appPath: removed[0] || existing[0]
262
+ };
263
+ }
264
+ return { success: true, removed: true, appPath: removed[0] || existing[0] };
265
+ }
266
+
267
+ async function findLocalServerPort(preferredPorts = []) {
268
+ const http = require('http');
269
+
270
+ const candidates = [];
271
+ const seen = new Set();
272
+ for (const port of preferredPorts) {
273
+ const n = Number.parseInt(String(port), 10);
274
+ if (!Number.isFinite(n) || n <= 0 || n > 65535) continue;
275
+ if (seen.has(n)) continue;
276
+ seen.add(n);
277
+ candidates.push(n);
278
+ }
279
+
280
+ const defaultPorts = [3001, 80, 8080, 8443, 9001];
281
+ for (const port of defaultPorts) {
282
+ if (seen.has(port)) continue;
283
+ seen.add(port);
284
+ candidates.push(port);
285
+ }
286
+
287
+ const probe = (port) => new Promise(resolve => {
288
+ const req = http.request({
289
+ hostname: '127.0.0.1',
290
+ port,
291
+ path: '/api/a2a/ping',
292
+ method: 'GET',
293
+ timeout: 800
294
+ }, (res) => {
295
+ res.resume();
296
+ resolve(res.statusCode === 200);
297
+ });
298
+ req.on('error', () => resolve(false));
299
+ req.on('timeout', () => { req.destroy(); resolve(false); });
300
+ req.end();
301
+ });
302
+
303
+ for (const port of candidates) {
304
+ // eslint-disable-next-line no-await-in-loop
305
+ const ok = await probe(port);
306
+ if (ok) return port;
307
+ }
308
+ return null;
309
+ }
310
+
311
+ // Parse arguments
312
+ function parseArgs(argv) {
313
+ const args = { _: [], flags: {} };
314
+ let i = 2;
315
+ while (i < argv.length) {
316
+ if (argv[i].startsWith('--')) {
317
+ const key = argv[i].slice(2);
318
+ const val = argv[i + 1] && !argv[i + 1].startsWith('-') ? argv[++i] : true;
319
+ args.flags[key] = val;
320
+ } else if (argv[i].startsWith('-') && argv[i].length === 2) {
321
+ const key = argv[i].slice(1);
322
+ const val = argv[i + 1] && !argv[i + 1].startsWith('-') ? argv[++i] : true;
323
+ args.flags[key] = val;
324
+ } else {
325
+ args._.push(argv[i]);
326
+ }
327
+ i++;
328
+ }
329
+ return args;
330
+ }
331
+
332
+ async function promptYesNo(question) {
333
+ const q = String(question || '');
334
+ // Support both bracket and paren styles: [Y/n], (y/N), etc.
335
+ // Convention: uppercase letter is the default when user presses Enter.
336
+ const defaultValue = q.includes('y/N')
337
+ ? false
338
+ : q.includes('Y/n')
339
+ ? true
340
+ : true;
341
+
342
+ if (!isInteractiveShell()) {
343
+ return defaultValue;
344
+ }
345
+
346
+ return await new Promise(resolve => {
347
+ const rl = require('readline').createInterface({ input: process.stdin, output: process.stdout });
348
+ rl.question(question, (answer) => {
349
+ rl.close();
350
+ const normalized = String(answer || '').trim().toLowerCase();
351
+ if (!normalized) return resolve(defaultValue);
352
+ resolve(normalized === 'y' || normalized === 'yes');
353
+ });
354
+ });
355
+ }
356
+
357
+ function isInteractiveShell() {
358
+ return Boolean(process.stdin && process.stdout && process.stdin.isTTY && process.stdout.isTTY);
359
+ }
360
+
361
+ async function promptText(question, defaultValue = '') {
362
+ if (!isInteractiveShell()) {
363
+ return defaultValue;
364
+ }
365
+ return await new Promise(resolve => {
366
+ const rl = require('readline').createInterface({ input: process.stdin, output: process.stdout });
367
+ rl.question(question, (answer) => {
368
+ rl.close();
369
+ const cleaned = String(answer || '').trim();
370
+ resolve(cleaned || defaultValue);
371
+ });
372
+ });
373
+ }
374
+
375
+ function parsePort(raw, fallback = null) {
376
+ const parsed = Number.parseInt(String(raw || '').trim(), 10);
377
+ if (Number.isFinite(parsed) && parsed > 0 && parsed <= 65535) {
378
+ return parsed;
379
+ }
380
+ return fallback;
381
+ }
382
+
383
+ function printStepHeader(label) {
384
+ const clean = String(label || '').trim();
385
+ const innerWidth = Math.max(62, clean.length + 12);
386
+ const padding = Math.max(0, innerWidth - clean.length);
387
+ const left = Math.floor(padding / 2);
388
+ const right = Math.max(0, padding - left);
389
+ console.log('\n' + '╔' + '═'.repeat(innerWidth) + '╗');
390
+ console.log(`║${' '.repeat(left)}${clean}${' '.repeat(right)}║`);
391
+ console.log('╚' + '═'.repeat(innerWidth) + '╝');
392
+ }
393
+
394
+ function printSection(title) {
395
+ console.log('\n━━━ ' + title + ' ━━━');
396
+ }
397
+
398
+ async function inspectPorts(preferredPort = null) {
399
+ const candidates = [];
400
+ if (preferredPort) {
401
+ candidates.push(preferredPort);
402
+ }
403
+ candidates.push(80);
404
+ for (let p = 3001; p < 3021; p += 1) {
405
+ if (!candidates.includes(p)) candidates.push(p);
406
+ }
407
+
408
+ const { tryBindPort } = require('../src/lib/port-scanner');
409
+ const results = [];
410
+ for (const port of candidates) {
411
+ const r = await tryBindPort(port);
412
+ results.push({
413
+ port,
414
+ available: Boolean(r.ok),
415
+ blocked: !r.ok && r.code === 'EACCES',
416
+ code: r.code || null
417
+ });
418
+ }
419
+ return results;
420
+ }
421
+
422
+ function summarizePortResults(portResults) {
423
+ return portResults.map(item => {
424
+ if (item.available) return `Port ${item.port}: available ✓`;
425
+ if (item.blocked) return `Port ${item.port}: requires elevated privileges`;
426
+ return `Port ${item.port}: in use`;
427
+ });
428
+ }
429
+
430
+ /**
431
+ * Identify what process is using a given port.
432
+ * Returns { pid, name } or null if detection fails.
433
+ */
434
+ function identifyPortProcess(port) {
435
+ const p = Number(port);
436
+ if (!Number.isFinite(p) || p <= 0) return null;
437
+ const { execSync } = require('child_process');
438
+ // Try lsof first (most common on Linux/macOS)
439
+ try {
440
+ const out = execSync(`lsof -i :${p} -sTCP:LISTEN -t 2>/dev/null`, { encoding: 'utf8', timeout: 5000 }).trim();
441
+ if (out) {
442
+ const pid = out.split('\n')[0].trim();
443
+ let name = 'unknown';
444
+ try {
445
+ name = execSync(`ps -p ${pid} -o comm= 2>/dev/null`, { encoding: 'utf8', timeout: 3000 }).trim();
446
+ } catch (e) { /* best-effort */ }
447
+ return { pid: Number(pid), name };
448
+ }
449
+ } catch (e) { /* lsof not available or failed */ }
450
+
451
+ // Fallback: ss (Linux)
452
+ try {
453
+ const out = execSync(`ss -tlnp 'sport = :${p}' 2>/dev/null`, { encoding: 'utf8', timeout: 5000 });
454
+ const pidMatch = out.match(/pid=(\d+)/);
455
+ const nameMatch = out.match(/\("([^"]+)"/);
456
+ if (pidMatch) {
457
+ return { pid: Number(pidMatch[1]), name: nameMatch ? nameMatch[1] : 'unknown' };
458
+ }
459
+ } catch (e) { /* ss not available */ }
460
+
461
+ return null;
462
+ }
463
+
464
+ /**
465
+ * When port 80 is unavailable, prompt the user with fallback options.
466
+ * Returns { strategy: 'kill' | 'proxy' | 'continue', port: number }
467
+ *
468
+ * Non-interactive: auto-returns 'continue' with a printed warning.
469
+ */
470
+ async function promptPortFallbackStrategy(fallbackPort, interactive) {
471
+ const processInfo = identifyPortProcess(80);
472
+
473
+ console.log('\n ┌─────────────────────────────────────────────────────────────────┐');
474
+ console.log(' │ ⚠ PORT 80 IS UNAVAILABLE │');
475
+ console.log(' └─────────────────────────────────────────────────────────────────┘');
476
+ console.log('');
477
+ if (processInfo) {
478
+ console.log(` Port 80 is held by: ${processInfo.name} (PID ${processInfo.pid})`);
479
+ } else {
480
+ console.log(' Port 80 is in use by another process (could not identify).');
481
+ }
482
+ console.log('');
483
+ console.log(' Why this matters:');
484
+ console.log(' - Port 80 is the default HTTP port — no firewall config needed');
485
+ console.log(` - Fallback port ${fallbackPort} may be blocked by the caller's firewall`);
486
+ console.log(` - If the server restarts on a different port, all invite URLs break`);
487
+ console.log(` - Invite URLs with non-standard ports look like: a2a://host:${fallbackPort}/token`);
488
+ console.log('');
489
+
490
+ if (!interactive) {
491
+ console.log(` Non-interactive mode: continuing on port ${fallbackPort}.`);
492
+ console.log(' Set up a reverse proxy (port 80 → ' + fallbackPort + ') for production use.\n');
493
+ return { strategy: 'continue', port: fallbackPort };
494
+ }
495
+
496
+ console.log(' Options:');
497
+ if (processInfo) {
498
+ console.log(` 1) Kill ${processInfo.name} (PID ${processInfo.pid}) and use port 80`);
499
+ } else {
500
+ console.log(' 1) Kill the process on port 80 and retry');
501
+ }
502
+ console.log(` 2) Set up a reverse proxy (port 80 → ${fallbackPort})`);
503
+ console.log(` 3) Continue on port ${fallbackPort} (not recommended for production)`);
504
+ console.log('');
505
+
506
+ const choice = await promptText(' Choose [1/2/3]: ', '2');
507
+ const normalized = String(choice).trim();
508
+
509
+ if (normalized === '1') {
510
+ return { strategy: 'kill', port: 80, processInfo };
511
+ } else if (normalized === '3') {
512
+ console.log(`\n ⚠ Continuing on port ${fallbackPort}.`);
513
+ console.log(` Invite URLs will include :${fallbackPort} and may not be reachable externally.`);
514
+ console.log(' You can set up a reverse proxy later with: a2a config --help\n');
515
+ return { strategy: 'continue', port: fallbackPort };
516
+ } else {
517
+ // Default: reverse proxy (option 2)
518
+ return { strategy: 'proxy', port: fallbackPort };
519
+ }
520
+ }
521
+
522
+ /**
523
+ * Attempt to kill the process on a given port.
524
+ * Returns true if kill succeeded and port is now available.
525
+ */
526
+ async function killPortProcess(processInfo) {
527
+ if (!processInfo || !Number.isFinite(processInfo.pid)) return false;
528
+ const { execSync } = require('child_process');
529
+ try {
530
+ console.log(` Killing ${processInfo.name} (PID ${processInfo.pid})...`);
531
+ execSync(`kill ${processInfo.pid}`, { timeout: 5000 });
532
+ // Wait briefly for the port to free up
533
+ await new Promise(r => setTimeout(r, 1000));
534
+ const { tryBindPort } = require('../src/lib/port-scanner');
535
+ const result = await tryBindPort(80);
536
+ if (result.ok) {
537
+ console.log(' ✅ Port 80 is now available.');
538
+ return true;
539
+ }
540
+ console.log(' Port 80 is still in use after kill. The process may require sudo to stop.');
541
+ return false;
542
+ } catch (e) {
543
+ console.log(` Could not kill process: ${e.message}`);
544
+ console.log(' You may need to run: sudo kill ' + processInfo.pid);
545
+ return false;
546
+ }
547
+ }
548
+
549
+ /**
550
+ * Detect installed web servers and generate reverse proxy config.
551
+ * Returns { hasNginx, hasCaddy, nginxConfig, caddyConfig }.
552
+ */
553
+ function generateProxyConfig(backendPort) {
554
+ const { spawnSync } = require('child_process');
555
+ const hasNginx = spawnSync('which', ['nginx'], { encoding: 'utf8' }).status === 0;
556
+ const hasCaddy = spawnSync('which', ['caddy'], { encoding: 'utf8' }).status === 0;
557
+
558
+ const nginxConfig = [
559
+ '# ══════════════════════════════════════════════════════════════',
560
+ '# A2A (Agent-to-Agent) Protocol Proxy',
561
+ '# ══════════════════════════════════════════════════════════════',
562
+ '# Routes federation requests from port 80 to the local',
563
+ `# A2A server on port ${backendPort}.`,
564
+ '#',
565
+ '# Protocol: https://github.com/onthegonow/a2a_calling',
566
+ '# All requests to /api/a2a/* are agent-to-agent API calls.',
567
+ '# ══════════════════════════════════════════════════════════════',
568
+ 'location /api/a2a/ {',
569
+ ` proxy_pass http://127.0.0.1:${backendPort}/api/a2a/;`,
570
+ ' proxy_http_version 1.1;',
571
+ ' proxy_set_header Host $host;',
572
+ ' proxy_set_header X-Real-IP $remote_addr;',
573
+ ' proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;',
574
+ ' proxy_set_header X-Forwarded-Proto $scheme;',
575
+ '}'
576
+ ].join('\n');
577
+
578
+ const caddyConfig = [
579
+ '# A2A (Agent-to-Agent) Protocol Proxy',
580
+ `# Routes federation requests to local A2A server on port ${backendPort}`,
581
+ '# Protocol: https://github.com/onthegonow/a2a_calling',
582
+ 'handle /api/a2a/* {',
583
+ ` reverse_proxy 127.0.0.1:${backendPort}`,
584
+ '}'
585
+ ].join('\n');
586
+
587
+ return { hasNginx, hasCaddy, nginxConfig, caddyConfig };
588
+ }
589
+
590
+ function extractNameFromPersonality(notes) {
591
+ if (!notes || typeof notes !== 'string') return null;
592
+ const patterns = [
593
+ /(?:I'm|I am|My name is|Name:|Owner:)\s+([A-Z][a-z]+(?:\s+[A-Z][a-z]+)?)/,
594
+ /^([A-Z][a-z]+(?:\s+[A-Z][a-z]+)?)\s+(?:is|here|speaking)/
595
+ ];
596
+ for (const p of patterns) {
597
+ const m = notes.match(p);
598
+ if (m && m[1]) return m[1].trim();
599
+ }
600
+ return null;
601
+ }
602
+
603
+ async function handleDisclosureSubmit(args, commandLabel = 'onboard') {
604
+ const submitRaw = args.flags.submit;
605
+ if (!submitRaw) return false;
606
+
607
+ const { A2AConfig } = require('../src/lib/config');
608
+ const {
609
+ validateDisclosureSubmission,
610
+ saveManifest,
611
+ MANIFEST_FILE
612
+ } = require('../src/lib/disclosure');
613
+
614
+ const config = new A2AConfig();
615
+ const submitCommand = commandLabel === 'quickstart'
616
+ ? 'a2a quickstart --submit'
617
+ : 'a2a onboard --submit';
618
+
619
+ let parsed;
620
+ try {
621
+ parsed = JSON.parse(String(submitRaw));
622
+ } catch (e) {
623
+ console.error('\nInvalid JSON in --submit flag.');
624
+ console.error(` Parse error: ${e.message}\n`);
625
+ process.exit(1);
626
+ }
627
+
628
+ const result = validateDisclosureSubmission(parsed);
629
+ if (!result.valid) {
630
+ console.error('\nDisclosure submission validation failed:\n');
631
+ result.errors.forEach(err => console.error(` - ${err}`));
632
+ console.error(`\nFix the errors above and resubmit with: ${submitCommand} '<json>'\n`);
633
+ process.exit(1);
634
+ }
635
+
636
+ saveManifest(result.manifest);
637
+ console.log('\nStep 3 of 4: Disclosure manifest saved.');
638
+ console.log(` Manifest: ${MANIFEST_FILE}`);
639
+
640
+ // Sync tier config from manifest
641
+ const manifest = result.manifest;
642
+
643
+ // Helper to extract topic names
644
+ function getTierTopics(tierData) {
645
+ if (!tierData || !Array.isArray(tierData.topics)) return [];
646
+ return tierData.topics.map(t => String(t && t.topic || '').trim()).filter(Boolean);
647
+ }
648
+
649
+ // Helper to extract allowed tools per tier from the disclosure manifest.
650
+ function getTierTools(tierData) {
651
+ if (!tierData || !Array.isArray(tierData.allowed_tools)) return [];
652
+ const seen = new Set();
653
+ const out = [];
654
+ for (const tool of tierData.allowed_tools) {
655
+ const cleaned = String(tool || '').trim();
656
+ if (!cleaned) continue;
657
+ const key = cleaned.toLowerCase();
658
+ if (seen.has(key)) continue;
659
+ seen.add(key);
660
+ out.push(cleaned);
661
+ }
662
+ return out;
663
+ }
664
+
665
+ const tiersData = manifest.tiers || {};
666
+
667
+ // Derive goals from disclosure objectives (used in tier config and token creation)
668
+ const disclosureObjectives = (tiersData.public?.objectives || [])
669
+ .map(o => typeof o === 'string' ? o : (o && o.objective || ''))
670
+ .map(s => s.trim().toLowerCase().replace(/\s+/g, '-').slice(0, 60))
671
+ .filter(Boolean);
672
+
673
+ const tokenGoals = disclosureObjectives.length > 0
674
+ ? [...new Set(disclosureObjectives)].slice(0, 5)
675
+ : ['grow-network', 'find-collaborators', 'build-in-public'];
676
+
677
+ try {
678
+ const publicTools = getTierTools(tiersData.public);
679
+ const friendsTools = [...publicTools, ...getTierTools(tiersData.friends)];
680
+ const familyTools = [...friendsTools, ...getTierTools(tiersData.family)];
681
+
682
+ const publicTierPatch = {
683
+ topics: getTierTopics(tiersData.public),
684
+ goals: tokenGoals
685
+ };
686
+ if (publicTools.length > 0) publicTierPatch.allowed_tools = publicTools;
687
+
688
+ const friendsTierPatch = {
689
+ topics: [...getTierTopics(tiersData.public), ...getTierTopics(tiersData.friends)]
690
+ };
691
+ if (friendsTools.length > 0) friendsTierPatch.allowed_tools = friendsTools;
692
+
693
+ const familyTierPatch = {
694
+ topics: [...getTierTopics(tiersData.public), ...getTierTopics(tiersData.friends), ...getTierTopics(tiersData.family)]
695
+ };
696
+ if (familyTools.length > 0) familyTierPatch.allowed_tools = familyTools;
697
+
698
+ config.setTier('public', publicTierPatch);
699
+ config.setTier('friends', friendsTierPatch);
700
+ config.setTier('family', familyTierPatch);
701
+ } catch (err) {
702
+ console.error(` Warning: could not sync tier config: ${err.message}`);
703
+ }
704
+
705
+ // If already onboarded, this is a topic update — no invite generation needed
706
+ if (config.isOnboarded()) {
707
+ console.log('\nDisclosure topics updated. Your agent will use these on the next inbound call.\n');
708
+ return true;
709
+ }
710
+
711
+ console.log('\nStep 4 of 4: Generating your first invite...\n');
712
+
713
+ // Extract identity from disclosure submission (parsed = raw JSON, result = validated)
714
+ const ownerName = parsed.owner_name
715
+ || extractNameFromPersonality(result.manifest?.personality_notes)
716
+ || process.env.USER
717
+ || 'Agent Owner';
718
+
719
+ const agentName = args.flags.name
720
+ || parsed.agent_name
721
+ || config.getAgent().name
722
+ || process.env.A2A_AGENT_NAME
723
+ || `${ownerName}'s Agent`;
724
+
725
+ // Save identity to config
726
+ config.setAgent({ name: agentName, owner_name: ownerName });
727
+
728
+ const hostname = config.getAgent().hostname || process.env.A2A_HOSTNAME || 'localhost';
729
+
730
+ const publicTopics = getTierTopics(tiersData.public);
731
+ const publicTools = getTierTools(tiersData.public);
732
+
733
+ const { token } = store.create({
734
+ name: agentName,
735
+ owner: ownerName,
736
+ permissions: 'public',
737
+ disclosure: 'minimal',
738
+ expires: 'never',
739
+ maxCalls: null,
740
+ allowedTopics: publicTopics,
741
+ allowedGoals: tokenGoals,
742
+ allowedTools: publicTools.length > 0 ? publicTools : null,
743
+ notify: 'all'
744
+ });
745
+
746
+ const inviteUrl = `a2a://${hostname}/${token}`;
747
+ console.log(` Invite URL: ${inviteUrl}`);
748
+ console.log(' Share this invite to let other agents call you.\n');
749
+
750
+ config.completeOnboarding();
751
+ console.log('Onboarding complete.\n');
752
+ console.log(` Config: ${CONFIG_PATH}`);
753
+ console.log(` Disclosure: ${MANIFEST_FILE}`);
754
+ console.log(` Invite: ${inviteUrl}\n`);
755
+
756
+ // Native app install should be part of the onboarding tail on macOS so users
757
+ // don't end up launching the app before a2a setup is complete.
758
+ if (os.platform() === 'darwin' && !findNativeApp()) {
759
+ if (isInteractiveShell()) {
760
+ const installNow = await promptYesNo('Install the native macOS app? [Y/n] ');
761
+ if (installNow) {
762
+ const result = installNativeMacApp({ force: false, quiet: false });
763
+ if (result.success) {
764
+ if (result.reason === 'already_current') {
765
+ console.log(`Native app already installed at current version (${result.version}).`);
766
+ console.log(`Path: ${result.appPath}\n`);
767
+ } else {
768
+ console.log(`Native app installed (v${result.version}).`);
769
+ console.log(`Path: ${result.appPath}\n`);
770
+ }
771
+ } else {
772
+ console.warn(`Native app install failed: ${result.error || 'unknown error'}`);
773
+ console.warn('You can retry with: a2a app install\n');
774
+ }
775
+ } else {
776
+ console.log('You can install the native app later with: a2a app install\n');
777
+ }
778
+ } else {
779
+ console.log('Install the native macOS app with: a2a app install\n');
780
+ }
781
+ }
782
+
783
+ return true;
784
+ }
785
+
786
+ async function resolveInviteHostname() {
787
+ const { resolveInviteHost } = require('../src/lib/invite-host');
788
+
789
+ try {
790
+ const { A2AConfig } = require('../src/lib/config');
791
+ const config = new A2AConfig();
792
+ const agent = config.getAgent() || {};
793
+ const onboarding = config.getAll().onboarding || {};
794
+
795
+ // If hostname is set without a port (e.g., "149.28.213.47"), assume port 80
796
+ // (user configured reverse proxy or direct bind to 80)
797
+ // If hostname has a port (e.g., "149.28.213.47:3007"), use that port
798
+ // If no hostname set, use server_port from onboarding
799
+ const hostname = agent.hostname || '';
800
+ const hasExplicitPort = hostname.includes(':') && !hostname.startsWith('[');
801
+
802
+ let defaultPort;
803
+ if (hasExplicitPort) {
804
+ defaultPort = null; // Will be parsed from hostname
805
+ } else if (hostname && !hostname.includes('localhost')) {
806
+ // External hostname without port = assume port 80 (reverse proxy or direct)
807
+ defaultPort = 80;
808
+ } else {
809
+ // Local or no hostname - use actual server port
810
+ defaultPort = onboarding.server_port || process.env.PORT || process.env.A2A_PORT || 80;
811
+ }
812
+
813
+ const resolved = await resolveInviteHost({
814
+ config,
815
+ defaultPort
816
+ });
817
+ return resolved;
818
+ } catch (err) {
819
+ return resolveInviteHost({
820
+ fallbackHost: process.env.OPENCLAW_HOSTNAME || process.env.HOSTNAME || 'localhost',
821
+ defaultPort: process.env.PORT || process.env.A2A_PORT || 80
822
+ });
823
+ }
824
+ }
825
+
826
+ // Commands
827
+ const commands = {
828
+ create: async (args) => {
829
+ const { A2AConfig } = require('../src/lib/config');
830
+ const { loadManifest, getTopicsForTier } = require('../src/lib/disclosure');
831
+ const config = new A2AConfig();
832
+
833
+ // Parse max-calls: number, 'unlimited', or default (unlimited)
834
+ let maxCalls = null; // Default: unlimited
835
+ if (args.flags['max-calls']) {
836
+ if (args.flags['max-calls'] === 'unlimited') {
837
+ maxCalls = null;
838
+ } else {
839
+ maxCalls = parseInt(args.flags['max-calls']) || null;
840
+ }
841
+ }
842
+
843
+ // Get tier from --tier or --permissions flag
844
+ const tier = args.flags.tier || args.flags.t || args.flags.permissions || args.flags.p || 'public';
845
+ const configTier = config.getTiers?.()[tier] || {};
846
+
847
+ // Get owner from flag or config
848
+ const configAgent = config.getAgent() || {};
849
+ const ownerName = args.flags.owner || args.flags.o || configAgent.owner || configAgent.name || null;
850
+
851
+ // Get topics from disclosure manifest based on tier (with inheritance)
852
+ const tierTopics = getTopicsForTier(tier);
853
+
854
+ // Parse custom topics if provided, otherwise use tier topics
855
+ let allowedTopics;
856
+ if (args.flags.topics) {
857
+ allowedTopics = args.flags.topics.split(',').map(t => t.trim());
858
+ } else if (tierTopics.topics && tierTopics.topics.length > 0) {
859
+ allowedTopics = tierTopics.topics.map(t => t.topic || t);
860
+ } else {
861
+ allowedTopics = null;
862
+ }
863
+
864
+ // Get objectives from disclosure
865
+ const objectives = tierTopics.objectives || [];
866
+ const allowedTools = args.flags.tools
867
+ ? String(args.flags.tools).split(',').map(t => t.trim()).filter(Boolean)
868
+ : (Array.isArray(configTier.allowed_tools) ? configTier.allowed_tools : null);
869
+ const timeoutMsRaw = args.flags['timeout-ms'] || args.flags.timeout_ms;
870
+ const timeoutMs = timeoutMsRaw ? Number.parseInt(String(timeoutMsRaw), 10) : null;
871
+
872
+ const { token, record } = store.create({
873
+ name: args.flags.name || args.flags.n || 'unnamed',
874
+ owner: ownerName,
875
+ expires: args.flags.expires || args.flags.e || 'never',
876
+ permissions: tier,
877
+ notify: args.flags.notify || 'all',
878
+ maxCalls,
879
+ allowedTopics,
880
+ allowedGoals: objectives.map(o => o.objective || o),
881
+ allowedTools,
882
+ timeoutMs
883
+ });
884
+
885
+ const resolvedHost = await resolveInviteHostname();
886
+ const hostname = resolvedHost.host;
887
+ const inviteUrl = `a2a://${hostname}/${token}`;
888
+
889
+ const expiresText = record.expires_at
890
+ ? new Date(record.expires_at).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })
891
+ : 'never';
892
+
893
+ if (resolvedHost.warnings && resolvedHost.warnings.length) {
894
+ for (const w of resolvedHost.warnings) {
895
+ console.warn(`\n⚠️ ${w}`);
896
+ }
897
+ console.warn('');
898
+ }
899
+
900
+ // Auto-link to contact if specified
901
+ const linkContact = args.flags.link || args.flags.l;
902
+ if (linkContact) {
903
+ const linkResult = store.linkTokenToContact(linkContact, record.id);
904
+ if (linkResult.success) {
905
+ console.log(`✅ Token created & linked to ${linkContact}\n`);
906
+ } else {
907
+ console.log(`✅ Token created (link failed: ${linkResult.error})\n`);
908
+ }
909
+ } else {
910
+ console.log(`✅ A2A token created\n`);
911
+ }
912
+
913
+ console.log(`Name: ${record.name}`);
914
+ if (record.owner) console.log(`Owner: ${record.owner}`);
915
+ console.log(`Expires: ${record.expires_at || 'never'}`);
916
+ console.log(`Tier: ${record.tier}`);
917
+ console.log(`Topics: ${record.allowed_topics.join(', ')}`);
918
+ if (Array.isArray(record.allowed_tools) && record.allowed_tools.length > 0) {
919
+ console.log(`Tools: ${record.allowed_tools.join(', ')}`);
920
+ }
921
+ console.log(`Notify: ${record.notify}`);
922
+ console.log(`Max calls: ${record.max_calls || 'unlimited'}`);
923
+ if (record.timeout_ms) console.log(`Turn timeout: ${record.timeout_ms}ms`);
924
+ if (linkContact) console.log(`Linked to: ${linkContact}`);
925
+ console.log(`\nTo revoke: a2a revoke ${record.id}`);
926
+ console.log(`\n${'─'.repeat(50)}`);
927
+ console.log(`📋 SHAREABLE INVITE (copy everything below):`);
928
+ console.log(`${'─'.repeat(50)}\n`);
929
+
930
+ // Get agent name from config (reuse configAgent from earlier)
931
+ const myAgentName = configAgent.name || 'my agent';
932
+ const ownerText = record.owner;
933
+
934
+ // Format topics as bullet list
935
+ const topicsArray = record.allowed_topics || [];
936
+ const topicsList = topicsArray.length > 0
937
+ ? topicsArray.map(t => ` • ${t}`).join('\n')
938
+ : '';
939
+
940
+ // Format objectives as bullet list
941
+ const goalsArray = record.allowed_goals || [];
942
+ const goalsList = goalsArray.length > 0
943
+ ? goalsArray.map(g => ` • ${g}`).join('\n')
944
+ : '';
945
+
946
+ // Build invite header
947
+ const inviteHeader = ownerText
948
+ ? `**${ownerText}** invites you to connect with their agent **${myAgentName}**`
949
+ : `You're invited to connect with **${myAgentName}**`;
950
+
951
+ const invite = `🤝 **Agent-to-Agent Invite**
952
+
953
+ ${inviteHeader}
954
+
955
+ \`\`\`
956
+ ${inviteUrl}
957
+ \`\`\`
958
+ ${topicsList ? `\n💬 **Topics:**\n${topicsList}\n` : ''}${goalsList ? `\n🎯 **Goals:**\n${goalsList}\n` : ''}${expiresText !== 'never' ? `⏰ Expires: ${expiresText}\n` : ''}
959
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
960
+
961
+ 📦 **Getting Started**
962
+
963
+ **1️⃣ Install**
964
+ \`\`\`
965
+ npm install -g a2acalling
966
+ \`\`\`
967
+
968
+ **2️⃣ Quick Setup** _(first time only)_
969
+ \`\`\`
970
+ a2a quickstart
971
+ \`\`\`
972
+
973
+ **3️⃣ Add Contact**
974
+ \`\`\`
975
+ a2a add "${inviteUrl}" "${ownerText || 'friend'}"
976
+ \`\`\`
977
+
978
+ **4️⃣ Say Hello!**
979
+ \`\`\`
980
+ a2a call "${ownerText || 'friend'}" "Hello! My owner asked me to reach out."
981
+ \`\`\`
982
+
983
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
984
+
985
+ ⚡ **One-liner** _(already set up?)_
986
+ \`\`\`
987
+ a2a add "${inviteUrl}" "${ownerText || 'friend'}" && a2a call "${ownerText || 'friend'}" "Hello!"
988
+ \`\`\`
989
+
990
+ 🔗 Docs: https://github.com/onthegonow/a2a_calling`;
991
+
992
+ console.log(invite);
993
+ console.log(`\n${'─'.repeat(50)}`);
994
+ },
995
+
996
+ list: () => {
997
+ const tokens = store.list();
998
+ if (tokens.length === 0) {
999
+ console.log('No active A2A tokens.');
1000
+ return;
1001
+ }
1002
+
1003
+ console.log('Active A2A tokens:\n');
1004
+ for (const t of tokens) {
1005
+ const expired = t.expires_at && new Date(t.expires_at) < new Date();
1006
+ const status = expired ? '⚠️ EXPIRED' : '✅ Active';
1007
+ const tier = t.tier || 'public';
1008
+ const topics = t.allowed_topics || ['chat'];
1009
+ console.log(`${status} ${t.id}`);
1010
+ console.log(` Name: ${t.name}`);
1011
+ console.log(` Tier: ${tier} → ${topics.join(', ')}`);
1012
+ console.log(` Expires: ${t.expires_at || 'never'}`);
1013
+ console.log(` Calls: ${t.calls_made}${t.max_calls ? '/' + t.max_calls : ''}`);
1014
+ console.log();
1015
+ }
1016
+ },
1017
+
1018
+ revoke: (args) => {
1019
+ const id = args._[1];
1020
+ if (!id) {
1021
+ console.error('Usage: a2a revoke <token_id>');
1022
+ process.exit(1);
1023
+ }
1024
+
1025
+ const result = store.revoke(id);
1026
+ if (!result.success) {
1027
+ console.error(`Token not found: ${id}`);
1028
+ process.exit(1);
1029
+ }
1030
+
1031
+ console.log(`✅ Token revoked: ${result.record.name} (${result.record.id})`);
1032
+ },
1033
+
1034
+ add: (args) => {
1035
+ const url = args._[1];
1036
+ const name = args._[2] || args.flags.name;
1037
+
1038
+ if (!url) {
1039
+ console.error('Usage: a2a add <invite_url> [name]');
1040
+ process.exit(1);
1041
+ }
1042
+
1043
+ try {
1044
+ const result = store.addContact(url, { name });
1045
+ if (!result.success) {
1046
+ console.log(`Contact already registered: ${result.existing.name}`);
1047
+ return;
1048
+ }
1049
+ console.log(`✅ Contact added: ${result.contact.name} (${result.contact.host})`);
1050
+ } catch (err) {
1051
+ console.error(err.message);
1052
+ process.exit(1);
1053
+ }
1054
+ },
1055
+
1056
+ remotes: () => {
1057
+ // Alias for contacts
1058
+ commands.contacts({ _: ['contacts'], flags: {} });
1059
+ },
1060
+
1061
+ contacts: (args) => {
1062
+ const subcommand = args._[1];
1063
+
1064
+ // Sub-commands
1065
+ if (subcommand === 'add') return commands['contacts:add'](args);
1066
+ if (subcommand === 'show') return commands['contacts:show'](args);
1067
+ if (subcommand === 'edit') return commands['contacts:edit'](args);
1068
+ if (subcommand === 'ping') return commands['contacts:ping'](args);
1069
+ if (subcommand === 'link') return commands['contacts:link'](args);
1070
+ if (subcommand === 'rm' || subcommand === 'remove') return commands['contacts:rm'](args);
1071
+
1072
+ // Default: list contacts
1073
+ const contacts = store.listContacts();
1074
+ if (contacts.length === 0) {
1075
+ console.log('📇 No contacts yet.\n');
1076
+ console.log('Add one with: a2a contacts add <invite_url>');
1077
+ return;
1078
+ }
1079
+
1080
+ console.log(`📇 Agent Contacts (${contacts.length})\n`);
1081
+ for (const r of contacts) {
1082
+ const statusIcon = r.status === 'online' ? '🟢' : r.status === 'offline' ? '🔴' : '⚪';
1083
+ const ownerText = r.owner ? ` — ${r.owner}` : '';
1084
+
1085
+ // Permission badge from linked token (what YOU gave THEM)
1086
+ let permBadge = '';
1087
+ if (r.linked_token) {
1088
+ const tier = r.linked_token.tier || 'public';
1089
+ permBadge = tier === 'family' ? ' ⚡' : tier === 'friends' ? ' 🔧' : ' 🌐';
1090
+ }
1091
+
1092
+ console.log(`${statusIcon} ${r.name}${ownerText}${permBadge}`);
1093
+ if (r.tags && r.tags.length > 0) {
1094
+ console.log(` 🏷️ ${r.tags.join(', ')}`);
1095
+ }
1096
+ if (r.last_seen) {
1097
+ const ago = formatTimeAgo(new Date(r.last_seen));
1098
+ console.log(` 📍 Last seen: ${ago}`);
1099
+ }
1100
+ console.log();
1101
+ }
1102
+
1103
+ console.log('Legend: 🌐 public 🔧 friends ⚡ family');
1104
+ },
1105
+
1106
+ 'contacts:add': async (args) => {
1107
+ const url = args._[2];
1108
+ if (!url) {
1109
+ console.error('Usage: a2a contacts add <invite_url> [options]');
1110
+ console.error('Options:');
1111
+ console.error(' --name, -n Agent name');
1112
+ console.error(' --owner, -o Owner name');
1113
+ console.error(' --server-name Server label (optional)');
1114
+ console.error(' --notes Notes about this contact');
1115
+ console.error(' --tags Comma-separated tags');
1116
+ console.error(' --link Link to token ID you gave them');
1117
+ console.error(' --public-key Ed25519 public key (base64, or "fetch" to get from /status)');
1118
+ process.exit(1);
1119
+ }
1120
+
1121
+ const options = {
1122
+ name: args.flags.name || args.flags.n,
1123
+ owner: args.flags.owner || args.flags.o,
1124
+ server_name: args.flags['server-name'] || args.flags.server_name || args.flags.serverName || null,
1125
+ notes: args.flags.notes,
1126
+ tags: args.flags.tags ? args.flags.tags.split(',').map(t => t.trim()) : [],
1127
+ linkedTokenId: args.flags.link || null
1128
+ };
1129
+
1130
+ // A2A-52: fetch or accept public key for identity verification
1131
+ const pubKeyFlag = args.flags['public-key'] || args.flags.public_key || args.flags.publicKey;
1132
+ if (pubKeyFlag === 'fetch' || pubKeyFlag === true) {
1133
+ try {
1134
+ const client = new A2AClient({});
1135
+ const statusResult = await client.status(url);
1136
+ if (statusResult.public_key) {
1137
+ options.public_key = statusResult.public_key;
1138
+ const { fingerprint: fpFunc } = require('../src/lib/crypto');
1139
+ console.log(` Fetched public key: ${fpFunc(statusResult.public_key)}`);
1140
+ }
1141
+ } catch (fetchErr) {
1142
+ console.error(` Warning: could not fetch public key from /status: ${fetchErr.message}`);
1143
+ }
1144
+ } else if (pubKeyFlag && typeof pubKeyFlag === 'string') {
1145
+ options.public_key = pubKeyFlag;
1146
+ }
1147
+
1148
+ try {
1149
+ const result = store.addContact(url, options);
1150
+ if (!result.success) {
1151
+ console.log(`Contact already exists: ${result.existing.name}`);
1152
+ return;
1153
+ }
1154
+ console.log(`✅ Contact added: ${result.contact.name}`);
1155
+ if (result.contact.owner) console.log(` Owner: ${result.contact.owner}`);
1156
+ if (result.contact.server_name) console.log(` Server: ${result.contact.server_name}`);
1157
+ console.log(` Host: ${result.contact.host}`);
1158
+ if (options.linkedTokenId) {
1159
+ console.log(` Linked to token: ${options.linkedTokenId}`);
1160
+ } else {
1161
+ console.log(`\n💡 Link a token: a2a contacts link ${result.contact.name} <token_id>`);
1162
+ }
1163
+ } catch (err) {
1164
+ console.error(err.message);
1165
+ process.exit(1);
1166
+ }
1167
+ },
1168
+
1169
+ 'contacts:show': (args) => {
1170
+ const name = args._[2];
1171
+ if (!name) {
1172
+ console.error('Usage: a2a contacts show <name>');
1173
+ process.exit(1);
1174
+ }
1175
+
1176
+ // Get contact with linked token info
1177
+ const contacts = store.listContacts();
1178
+ const remote = contacts.find(r => r.name === name || r.id === name);
1179
+ if (!remote) {
1180
+ console.error(`Contact not found: ${name}`);
1181
+ process.exit(1);
1182
+ }
1183
+
1184
+ const statusIcon = remote.status === 'online' ? '🟢' : remote.status === 'offline' ? '🔴' : '⚪';
1185
+
1186
+ console.log(`\n${'═'.repeat(50)}`);
1187
+ console.log(`${statusIcon} ${remote.name}`);
1188
+ console.log(`${'═'.repeat(50)}\n`);
1189
+
1190
+ if (remote.owner) console.log(`👤 Owner: ${remote.owner}`);
1191
+ console.log(`🌐 Host: ${remote.host}`);
1192
+
1193
+ // Show linked token (permissions you gave them)
1194
+ if (remote.linked_token) {
1195
+ const t = remote.linked_token;
1196
+ const tier = t.tier || 'public';
1197
+ const topics = t.allowed_topics || ['chat'];
1198
+ const tierIcon = tier === 'family' ? '⚡' : tier === 'friends' ? '🔧' : '🌐';
1199
+ console.log(`🔐 Your token to them: ${t.id}`);
1200
+ console.log(` Tier: ${tierIcon} ${tier}`);
1201
+ console.log(` Topics: ${topics.join(', ')}`);
1202
+ console.log(` Calls: ${t.calls_made}${t.max_calls ? '/' + t.max_calls : ''}`);
1203
+ if (t.revoked) console.log(` ⚠️ REVOKED`);
1204
+ } else {
1205
+ console.log(`🔐 No linked token (you haven't given them access yet)`);
1206
+ }
1207
+
1208
+ // A2A-52: show cryptographic identity verification status
1209
+ if (remote.public_key) {
1210
+ const { fingerprint: fpFunc } = require('../src/lib/crypto');
1211
+ console.log(`🔑 Identity: verified`);
1212
+ console.log(` Fingerprint: ${fpFunc(remote.public_key)}`);
1213
+ } else {
1214
+ console.log(`🔑 Identity: unverified (no public key pinned)`);
1215
+ }
1216
+
1217
+ if (remote.tags && remote.tags.length > 0) {
1218
+ console.log(`🏷️ Tags: ${remote.tags.join(', ')}`);
1219
+ }
1220
+ if (remote.notes) {
1221
+ console.log(`📝 Notes: ${remote.notes}`);
1222
+ }
1223
+
1224
+ console.log(`\n📅 Added: ${new Date(remote.added_at).toLocaleDateString()}`);
1225
+ if (remote.last_seen) {
1226
+ console.log(`📍 Last seen: ${formatTimeAgo(new Date(remote.last_seen))}`);
1227
+ }
1228
+ if (remote.last_check) {
1229
+ console.log(`🔄 Last check: ${formatTimeAgo(new Date(remote.last_check))}`);
1230
+ }
1231
+
1232
+ console.log(`\n${'─'.repeat(50)}`);
1233
+ console.log(`Quick actions:`);
1234
+ console.log(` a2a contacts ping ${name}`);
1235
+ console.log(` a2a call ${name} "Hello!"`);
1236
+ if (!remote.linked_token) {
1237
+ console.log(` a2a contacts link ${name} <token_id>`);
1238
+ }
1239
+ console.log(`${'─'.repeat(50)}\n`);
1240
+ },
1241
+
1242
+ 'contacts:edit': (args) => {
1243
+ const name = args._[2];
1244
+ if (!name) {
1245
+ console.error('Usage: a2a contacts edit <name> [options]');
1246
+ console.error('Options:');
1247
+ console.error(' --name New name');
1248
+ console.error(' --owner Owner name');
1249
+ console.error(' --server-name Server label');
1250
+ console.error(' --notes Notes');
1251
+ console.error(' --tags Comma-separated tags');
1252
+ process.exit(1);
1253
+ }
1254
+
1255
+ const updates = {};
1256
+ if (args.flags.name) updates.name = args.flags.name;
1257
+ if (args.flags.owner) updates.owner = args.flags.owner;
1258
+ if (args.flags['server-name'] || args.flags.server_name || args.flags.serverName) updates.server_name = args.flags['server-name'] || args.flags.server_name || args.flags.serverName;
1259
+ if (args.flags.notes) updates.notes = args.flags.notes;
1260
+ if (args.flags.tags) updates.tags = args.flags.tags.split(',').map(t => t.trim());
1261
+
1262
+ if (Object.keys(updates).length === 0) {
1263
+ console.error('No updates specified. Use --name, --owner, --notes, or --tags');
1264
+ process.exit(1);
1265
+ }
1266
+
1267
+ const result = store.updateContact(name, updates);
1268
+ if (!result.success) {
1269
+ console.error(`Contact not found: ${name}`);
1270
+ process.exit(1);
1271
+ }
1272
+
1273
+ console.log(`✅ Contact updated: ${(result.contact || result.remote).name}`);
1274
+ },
1275
+
1276
+ 'contacts:link': (args) => {
1277
+ const contactName = args._[2];
1278
+ const tokenId = args._[3];
1279
+
1280
+ if (!contactName || !tokenId) {
1281
+ console.error('Usage: a2a contacts link <contact_name> <token_id>');
1282
+ console.error('\nLinks a token you created to a contact, showing what access they have.');
1283
+ console.error('\nExample:');
1284
+ console.error(' a2a contacts link Alice tok_abc123');
1285
+ process.exit(1);
1286
+ }
1287
+
1288
+ const result = store.linkTokenToContact(contactName, tokenId);
1289
+ if (!result.success) {
1290
+ if (result.error === 'contact_not_found') {
1291
+ console.error(`Contact not found: ${contactName}`);
1292
+ } else if (result.error === 'token_not_found') {
1293
+ console.error(`Token not found: ${tokenId}`);
1294
+ }
1295
+ process.exit(1);
1296
+ }
1297
+
1298
+ const permLabel = result.token.tier === 'family' ? '⚡ family' :
1299
+ result.token.tier === 'friends' ? '🔧 friends' : '🌐 public';
1300
+
1301
+ console.log(`✅ Linked token to contact`);
1302
+ console.log(` Contact: ${result.contact?.name || result.remote.name}`);
1303
+ console.log(` Token: ${result.token.id} (${result.token.name})`);
1304
+ console.log(` Permissions: ${permLabel}`);
1305
+ },
1306
+
1307
+ 'contacts:ping': async (args) => {
1308
+ const name = args._[2];
1309
+ if (!name) {
1310
+ console.error('Usage: a2a contacts ping <name>');
1311
+ process.exit(1);
1312
+ }
1313
+
1314
+ const remote = store.getContact(name);
1315
+ if (!remote) {
1316
+ console.error(`Contact not found: ${name}`);
1317
+ process.exit(1);
1318
+ }
1319
+
1320
+ const client = new A2AClient({});
1321
+ const url = `a2a://${remote.host}/${remote.token}`;
1322
+
1323
+ console.log(`🔍 Pinging ${remote.name}...`);
1324
+
1325
+ try {
1326
+ const result = await client.ping(url);
1327
+ store.updateContactStatus(name, 'online');
1328
+ console.log(`🟢 ${remote.name} is online`);
1329
+ console.log(` Agent: ${result.name}`);
1330
+ console.log(` Version: ${result.version}`);
1331
+
1332
+ // A2A-52: also fetch /status to refresh public key
1333
+ try {
1334
+ const statusResult = await client.status(url);
1335
+ if (statusResult.public_key) {
1336
+ const { fingerprint: fpFunc } = require('../src/lib/crypto');
1337
+ if (remote.public_key && remote.public_key !== statusResult.public_key) {
1338
+ console.log(` ⚠️ Public key changed!`);
1339
+ console.log(` Old: ${fpFunc(remote.public_key)}`);
1340
+ console.log(` New: ${fpFunc(statusResult.public_key)}`);
1341
+ }
1342
+ store.updateContact(name, { public_key: statusResult.public_key });
1343
+ console.log(` 🔑 Fingerprint: ${fpFunc(statusResult.public_key)}`);
1344
+ }
1345
+ } catch (_) {
1346
+ // /status fetch is best-effort during ping
1347
+ }
1348
+ } catch (err) {
1349
+ store.updateContactStatus(name, 'offline', err.message);
1350
+ console.log(`🔴 ${remote.name} is offline`);
1351
+ console.log(` Error: ${err.message}`);
1352
+ }
1353
+ },
1354
+
1355
+ 'contacts:rm': (args) => {
1356
+ const name = args._[2];
1357
+ if (!name) {
1358
+ console.error('Usage: a2a contacts rm <name>');
1359
+ process.exit(1);
1360
+ }
1361
+
1362
+ const result = store.removeContact(name);
1363
+ if (!result.success) {
1364
+ console.error(`Contact not found: ${name}`);
1365
+ process.exit(1);
1366
+ }
1367
+
1368
+ console.log(`✅ Contact removed: ${(result.contact || result.remote).name}`);
1369
+ },
1370
+
1371
+ // ========== CONVERSATIONS ==========
1372
+
1373
+ conversations: (args) => {
1374
+ const subcommand = args._[1];
1375
+
1376
+ if (subcommand === 'show') return commands['conversations:show'](args);
1377
+ if (subcommand === 'end') return commands['conversations:end'](args);
1378
+
1379
+ // Default: list conversations
1380
+ const cs = getConvStore();
1381
+ if (!cs) {
1382
+ console.log('💬 Conversation storage not available.');
1383
+ console.log('Install: npm install better-sqlite3');
1384
+ return;
1385
+ }
1386
+
1387
+ const { contact, status, limit = 20 } = args.flags;
1388
+ const conversations = cs.listConversations({
1389
+ contactId: contact,
1390
+ status,
1391
+ limit: parseInt(limit),
1392
+ includeMessages: true,
1393
+ messageLimit: 1
1394
+ });
1395
+
1396
+ if (conversations.length === 0) {
1397
+ console.log('💬 No conversations yet.');
1398
+ return;
1399
+ }
1400
+
1401
+ console.log(`💬 Conversations (${conversations.length})\n`);
1402
+ for (const conv of conversations) {
1403
+ const statusIcon = conv.status === 'concluded' ? '✅' : conv.status === 'timeout' ? '⏱️' : '💬';
1404
+ const timeAgo = formatTimeAgo(new Date(conv.last_message_at));
1405
+ const preview = conv.messages?.[0]?.content?.slice(0, 50) || '';
1406
+
1407
+ console.log(`${statusIcon} ${conv.id}`);
1408
+ console.log(` Contact: ${conv.contact_name || conv.contact_id || 'unknown'}`);
1409
+ console.log(` Messages: ${conv.message_count} | ${timeAgo}`);
1410
+ if (conv.summary) {
1411
+ console.log(` Summary: ${conv.summary.slice(0, 80)}...`);
1412
+ } else if (preview) {
1413
+ console.log(` Preview: "${preview}..."`);
1414
+ }
1415
+ if (conv.owner_relevance) {
1416
+ console.log(` Relevance: ${conv.owner_relevance}`);
1417
+ }
1418
+ console.log();
1419
+ }
1420
+ },
1421
+
1422
+ 'conversations:show': (args) => {
1423
+ const convId = args._[2];
1424
+ if (!convId) {
1425
+ console.error('Usage: a2a conversations show <conversation_id>');
1426
+ process.exit(1);
1427
+ }
1428
+
1429
+ const cs = getConvStore();
1430
+ if (!cs) {
1431
+ console.error('Conversation storage not available. Install: npm install better-sqlite3');
1432
+ process.exit(1);
1433
+ }
1434
+
1435
+ const context = cs.getConversationContext(convId, args.flags.messages || 20);
1436
+ if (!context) {
1437
+ console.error(`Conversation not found: ${convId}`);
1438
+ process.exit(1);
1439
+ }
1440
+
1441
+ console.log(`\n${'═'.repeat(60)}`);
1442
+ console.log(`💬 ${context.id}`);
1443
+ console.log(`${'═'.repeat(60)}\n`);
1444
+
1445
+ console.log(`👤 Contact: ${context.contact || 'unknown'}`);
1446
+ console.log(`📊 Status: ${context.status}`);
1447
+ console.log(`📝 Messages: ${context.messageCount}`);
1448
+ console.log(`📅 Started: ${new Date(context.startedAt).toLocaleString()}`);
1449
+ if (context.endedAt) {
1450
+ console.log(`🏁 Ended: ${new Date(context.endedAt).toLocaleString()}`);
1451
+ }
1452
+
1453
+ if (context.summary) {
1454
+ console.log(`\n${'─'.repeat(60)}`);
1455
+ console.log(`📋 Summary:\n${context.summary}`);
1456
+ }
1457
+
1458
+ if (context.ownerContext) {
1459
+ console.log(`\n${'─'.repeat(60)}`);
1460
+ console.log(`🔒 Owner Context (private):`);
1461
+ console.log(` Relevance: ${context.ownerContext.relevance || 'unknown'}`);
1462
+ if (context.ownerContext.summary) {
1463
+ console.log(` Summary: ${context.ownerContext.summary}`);
1464
+ }
1465
+ if (context.ownerContext.goalsTouched?.length) {
1466
+ console.log(` Goals: ${context.ownerContext.goalsTouched.join(', ')}`);
1467
+ }
1468
+ if (context.ownerContext.actionItems?.length) {
1469
+ console.log(` Actions: ${context.ownerContext.actionItems.join(', ')}`);
1470
+ }
1471
+ if (context.ownerContext.followUp) {
1472
+ console.log(` Follow-up: ${context.ownerContext.followUp}`);
1473
+ }
1474
+ if (context.ownerContext.notes) {
1475
+ console.log(` Notes: ${context.ownerContext.notes}`);
1476
+ }
1477
+ }
1478
+
1479
+ console.log(`\n${'─'.repeat(60)}`);
1480
+ console.log(`Recent messages:`);
1481
+ console.log(`${'─'.repeat(60)}`);
1482
+ for (const msg of context.recentMessages) {
1483
+ const role = msg.direction === 'inbound' ? '← In' : '→ Out';
1484
+ const time = new Date(msg.timestamp).toLocaleTimeString();
1485
+ console.log(`\n[${time}] ${role}:`);
1486
+ console.log(msg.content);
1487
+ }
1488
+ console.log(`\n${'═'.repeat(60)}\n`);
1489
+ },
1490
+
1491
+ 'conversations:end': async (args) => {
1492
+ const convId = args._[2];
1493
+ if (!convId) {
1494
+ console.error('Usage: a2a conversations end <conversation_id>');
1495
+ process.exit(1);
1496
+ }
1497
+
1498
+ const cs = getConvStore();
1499
+ if (!cs) {
1500
+ console.error('Conversation storage not available');
1501
+ process.exit(1);
1502
+ }
1503
+
1504
+ // For now, conclude without LLM summarizer
1505
+ const result = await cs.concludeConversation(convId, {});
1506
+
1507
+ if (!result.success) {
1508
+ console.error(`Failed to end conversation: ${result.error}`);
1509
+ process.exit(1);
1510
+ }
1511
+
1512
+ console.log(`✅ Conversation concluded: ${convId}`);
1513
+ if (result.summary) {
1514
+ console.log(`📋 Summary: ${result.summary}`);
1515
+ }
1516
+ },
1517
+
1518
+ call: async (args) => {
1519
+ let target = args._[1];
1520
+ const message = args._.slice(2).join(' ') || args.flags.message || args.flags.m;
1521
+
1522
+ if (!target || !message) {
1523
+ console.error('Usage: a2a call <contact_or_url> <message>');
1524
+ console.error(' --single Single-turn call (one message, one response)');
1525
+ console.error(' --min-turns N Minimum turns before close (default: 8)');
1526
+ console.error(' --max-turns N Maximum turns (default: 25)');
1527
+ process.exit(1);
1528
+ }
1529
+
1530
+ // Check if target is a contact name (not a URL)
1531
+ let url = target;
1532
+ let contactName = null;
1533
+ if (!target.startsWith('a2a://')) {
1534
+ const remote = store.getContact(target);
1535
+ if (remote) {
1536
+ url = `a2a://${remote.host}/${remote.token}`;
1537
+ contactName = remote.name;
1538
+ }
1539
+ }
1540
+
1541
+ const single = Boolean(args.flags.single);
1542
+ const callerName = args.flags.name || 'CLI User';
1543
+
1544
+ if (!single) {
1545
+ // Multi-turn conversation via ConversationDriver
1546
+ const { ConversationDriver } = require('../src/lib/conversation-driver');
1547
+ const { createRuntimeAdapter } = require('../src/lib/runtime-adapter');
1548
+ const { loadManifest } = require('../src/lib/disclosure');
1549
+
1550
+ const workspaceDir = process.env.A2A_WORKSPACE || process.env.OPENCLAW_WORKSPACE || process.cwd();
1551
+ const agentContext = {
1552
+ name: process.env.A2A_AGENT_NAME || process.env.AGENT_NAME || 'a2a-agent',
1553
+ owner: process.env.A2A_OWNER_NAME || process.env.USER || 'Agent Owner'
1554
+ };
1555
+
1556
+ const runtime = createRuntimeAdapter({ workspaceDir, agentContext });
1557
+ const cs = getConvStore();
1558
+ const disclosure = loadManifest();
1559
+
1560
+ const minTurns = parseInt(args.flags['min-turns']) || 8;
1561
+ const maxTurns = parseInt(args.flags['max-turns']) || 25;
1562
+
1563
+ // Build owner context from config for summarizer
1564
+ let ownerContext = {};
1565
+ let configTurnTimeoutMs = null;
1566
+ try {
1567
+ const { A2AConfig } = require('../src/lib/config');
1568
+ const config = new A2AConfig();
1569
+ const configAll = config.getAll();
1570
+ const tierGoals = configAll.tiers?.public?.goals || [];
1571
+ configTurnTimeoutMs = configAll.defaults?.turnTimeoutMs
1572
+ || configAll.defaults?.turn_timeout_ms
1573
+ || null;
1574
+ ownerContext = {
1575
+ goals: tierGoals,
1576
+ agentName: agentContext.name,
1577
+ ownerName: agentContext.owner
1578
+ };
1579
+ } catch (err) {
1580
+ // Best effort
1581
+ }
1582
+
1583
+ // A2A-52: load keypair for request signing in multi-turn calls
1584
+ const _multiKeypair = config.getKeypair();
1585
+ const driver = new ConversationDriver({
1586
+ runtime,
1587
+ agentContext,
1588
+ caller: { name: callerName },
1589
+ endpoint: url,
1590
+ convStore: cs,
1591
+ disclosure,
1592
+ minTurns,
1593
+ maxTurns,
1594
+ configTurnTimeoutMs,
1595
+ ownerContext,
1596
+ privateKey: _multiKeypair ? _multiKeypair.privateKey : null,
1597
+ publicKey: _multiKeypair ? _multiKeypair.publicKey : null,
1598
+ onTurn: (info) => {
1599
+ const preview = info.messagePreview.length >= 80
1600
+ ? info.messagePreview + '...'
1601
+ : info.messagePreview;
1602
+ console.log(` Turn ${info.turn} | ${info.phase} | overlap: ${info.overlapScore.toFixed(2)} | ${preview}`);
1603
+ }
1604
+ });
1605
+
1606
+ console.log(`📞 Starting multi-turn conversation with ${contactName || url}...`);
1607
+ console.log(` Min turns: ${minTurns} | Max turns: ${maxTurns}\n`);
1608
+
1609
+ try {
1610
+ const result = await driver.run(message);
1611
+
1612
+ if (contactName) {
1613
+ store.updateContactStatus(contactName, 'online');
1614
+ }
1615
+
1616
+ console.log(`\n✅ Conversation complete`);
1617
+ console.log(` Turns: ${result.turnCount}`);
1618
+ console.log(` Phase: ${result.collabState.phase}`);
1619
+ console.log(` Overlap: ${result.collabState.overlapScore.toFixed(2)}`);
1620
+ if (result.collabState.candidateCollaborations.length > 0) {
1621
+ console.log(` Collaborations: ${result.collabState.candidateCollaborations.join(', ')}`);
1622
+ }
1623
+ console.log(` Conversation ID: ${result.conversationId}`);
1624
+ if (result.summary) {
1625
+ console.log(`\n📋 Summary:\n${result.summary}`);
1626
+ }
1627
+ } catch (err) {
1628
+ if (contactName) {
1629
+ store.updateContactStatus(contactName, 'offline', err.message);
1630
+ }
1631
+ console.error(`❌ Multi-turn call failed: ${err.message}`);
1632
+ process.exit(1);
1633
+ }
1634
+ return;
1635
+ }
1636
+
1637
+ // Single-shot call (existing behavior)
1638
+ // A2A-52: load keypair for request signing
1639
+ const _callKeypair = config.getKeypair();
1640
+ const client = new A2AClient({
1641
+ caller: { name: callerName },
1642
+ privateKey: _callKeypair ? _callKeypair.privateKey : null,
1643
+ publicKey: _callKeypair ? _callKeypair.publicKey : null
1644
+ });
1645
+
1646
+ try {
1647
+ console.log(`📞 Calling ${contactName || url}...`);
1648
+ const response = await client.call(url, message);
1649
+
1650
+ // Update contact status on success
1651
+ if (contactName) {
1652
+ store.updateContactStatus(contactName, 'online');
1653
+ }
1654
+
1655
+ // Persist conversation locally
1656
+ const cs = getConvStore();
1657
+ if (cs) {
1658
+ try {
1659
+ // Use remote conversation ID if provided, otherwise generate a local one
1660
+ const convId = response.conversation_id || `conv_${Date.now()}_${crypto.randomBytes(4).toString('hex')}`;
1661
+
1662
+ const convResult = cs.startConversation({
1663
+ id: convId,
1664
+ contactId: contactName || null,
1665
+ contactName: contactName || null,
1666
+ direction: 'outbound'
1667
+ });
1668
+ if (convResult.success === false) {
1669
+ console.error(`⚠️ Failed to save conversation: ${convResult.error}`);
1670
+ } else {
1671
+ const outMsg = cs.addMessage(convId, {
1672
+ direction: 'outbound',
1673
+ role: 'user',
1674
+ content: message
1675
+ });
1676
+ if (outMsg.success === false) {
1677
+ console.error(`⚠️ Failed to save outbound message: ${outMsg.error}`);
1678
+ }
1679
+ if (response.response) {
1680
+ const inMsg = cs.addMessage(convId, {
1681
+ direction: 'inbound',
1682
+ role: 'assistant',
1683
+ content: response.response
1684
+ });
1685
+ if (inMsg.success === false) {
1686
+ console.error(`⚠️ Failed to save inbound message: ${inMsg.error}`);
1687
+ }
1688
+ }
1689
+ // Update response to include conversation ID for display
1690
+ if (!response.conversation_id) {
1691
+ response.conversation_id = convId;
1692
+ }
1693
+ }
1694
+ } catch (err) {
1695
+ console.error(`⚠️ Error persisting conversation: ${err.message}`);
1696
+ }
1697
+ }
1698
+
1699
+ console.log(`\n✅ Response:\n`);
1700
+ console.log(response.response);
1701
+ if (response.conversation_id) {
1702
+ console.log(`\n📝 Conversation ID: ${response.conversation_id}`);
1703
+ }
1704
+ } catch (err) {
1705
+ // Update contact status on failure
1706
+ if (contactName) {
1707
+ store.updateContactStatus(contactName, 'offline', err.message);
1708
+ }
1709
+ console.error(`❌ Call failed: ${err.message}`);
1710
+ process.exit(1);
1711
+ }
1712
+ },
1713
+
1714
+ ping: async (args) => {
1715
+ const url = args._[1];
1716
+ if (!url) {
1717
+ console.error('Usage: a2a ping <invite_url>');
1718
+ process.exit(1);
1719
+ }
1720
+
1721
+ const client = new A2AClient();
1722
+ const result = await client.ping(url);
1723
+
1724
+ if (result.pong) {
1725
+ console.log(`✅ Agent reachable at ${url}`);
1726
+ if (result.timestamp) {
1727
+ console.log(` Timestamp: ${result.timestamp}`);
1728
+ }
1729
+ } else {
1730
+ console.log(`❌ Agent not reachable at ${url}`);
1731
+ process.exit(1);
1732
+ }
1733
+ },
1734
+
1735
+ gui: async (args) => {
1736
+ // GUI is always safe to open even before onboarding.
1737
+ const tab = (args.flags.tab || args.flags.t || '').trim().toLowerCase();
1738
+ // A2A-41: 'settings' remains as backward-compat alias for 'permissions'
1739
+ const tabAliases = { settings: 'permissions' };
1740
+ const resolvedTab = tabAliases[tab] || tab;
1741
+ const allowedTabs = new Set(['contacts', 'calls', 'logs', 'permissions', 'invites']);
1742
+ const hash = allowedTabs.has(resolvedTab) ? `#${resolvedTab}` : '';
1743
+
1744
+ const urlFlag = args.flags.url;
1745
+ if (urlFlag) {
1746
+ const url = String(urlFlag);
1747
+ console.log(`Dashboard URL: ${url}`);
1748
+ const opened = openInBrowser(url);
1749
+ if (opened.attempted) {
1750
+ console.log(`Opening browser via: ${opened.command}`);
1751
+ } else {
1752
+ console.log('Could not auto-open browser.');
1753
+ }
1754
+ return;
1755
+ }
1756
+
1757
+ // Prefer native app on macOS (--browser flag forces browser)
1758
+ if (!args.flags.browser) {
1759
+ const nativeApp = findNativeApp();
1760
+ if (nativeApp) {
1761
+ console.log('Opening A2A Callbook native app...');
1762
+ const result = openInBrowser(nativeApp);
1763
+ if (result.attempted) {
1764
+ return;
1765
+ }
1766
+ }
1767
+ }
1768
+
1769
+ const preferred = [];
1770
+ if (args.flags.port || args.flags.p) preferred.push(args.flags.port || args.flags.p);
1771
+ if (process.env.A2A_PORT) preferred.push(process.env.A2A_PORT);
1772
+ if (process.env.PORT) preferred.push(process.env.PORT);
1773
+
1774
+ const port = await findLocalServerPort(preferred);
1775
+ if (!port) {
1776
+ console.log('Dashboard is not reachable on common ports.');
1777
+ console.log('Start the server (example):');
1778
+ console.log(' A2A_HOSTNAME="localhost:3001" a2a server --port 3001');
1779
+ console.log('Then open:');
1780
+ console.log(' http://127.0.0.1:3001/dashboard/');
1781
+ return;
1782
+ }
1783
+
1784
+ const url = `http://127.0.0.1:${port}/dashboard/${hash}`;
1785
+ console.log(`Dashboard URL: ${url}`);
1786
+ const opened = openInBrowser(url);
1787
+ if (opened.attempted) {
1788
+ console.log(`Opening browser via: ${opened.command}`);
1789
+ } else {
1790
+ console.log('Could not auto-open browser; open the URL above manually.');
1791
+ }
1792
+ },
1793
+
1794
+ dashboard: (args) => {
1795
+ // Alias for gui
1796
+ return commands.gui(args);
1797
+ },
1798
+
1799
+ status: async (args) => {
1800
+ const url = args._[1];
1801
+
1802
+ // If a URL is provided, check that remote agent's status
1803
+ if (url) {
1804
+ const client = new A2AClient();
1805
+ try {
1806
+ const status = await client.status(url);
1807
+ console.log(`A2A status for ${url}:\n`);
1808
+ console.log(JSON.stringify(status, null, 2));
1809
+ } catch (err) {
1810
+ console.error(`❌ Failed to get status: ${err.message}`);
1811
+ process.exit(1);
1812
+ }
1813
+ return;
1814
+ }
1815
+
1816
+ // No URL — show local server status
1817
+ const { A2AConfig } = require('../src/lib/config');
1818
+ const config = new A2AConfig();
1819
+ const onboarding = config.getOnboarding();
1820
+ const agent = config.getAgent();
1821
+
1822
+ console.log('A2A Local Status\n');
1823
+
1824
+ // Onboarding state
1825
+ const onboarded = onboarding.version === 2 && onboarding.step === 'complete';
1826
+ console.log(` Onboarding: ${onboarded ? '✅ Complete' : `⚠️ ${onboarding.step || 'not started'} (run: a2a quickstart)`}`);
1827
+ console.log(` Agent name: ${agent.name || '(not set)'}`);
1828
+ console.log(` Hostname: ${agent.hostname || '(not set)'}`);
1829
+
1830
+ // Check if server is running
1831
+ const preferred = [];
1832
+ if (onboarding.server_port) preferred.push(onboarding.server_port);
1833
+ const port = await findLocalServerPort(preferred);
1834
+ if (port) {
1835
+ console.log(` Server: ✅ Running on port ${port}`);
1836
+
1837
+ // Fetch dashboard status for more detail
1838
+ const http = require('http');
1839
+ try {
1840
+ const statusData = await new Promise((resolve, reject) => {
1841
+ const req = http.request({
1842
+ hostname: '127.0.0.1', port,
1843
+ path: '/api/a2a/dashboard/status',
1844
+ method: 'GET', timeout: 2000
1845
+ }, (res) => {
1846
+ let body = '';
1847
+ res.on('data', c => body += c);
1848
+ res.on('end', () => {
1849
+ try { resolve(JSON.parse(body)); } catch (e) { reject(e); }
1850
+ });
1851
+ });
1852
+ req.on('error', reject);
1853
+ req.on('timeout', () => { req.destroy(); reject(new Error('timeout')); });
1854
+ req.end();
1855
+ });
1856
+
1857
+ if (statusData.agent) {
1858
+ if (statusData.agent.owner_name) console.log(` Owner: ${statusData.agent.owner_name}`);
1859
+ }
1860
+ if (statusData.invite_host) {
1861
+ const ih = typeof statusData.invite_host === 'object' ? statusData.invite_host.host : statusData.invite_host;
1862
+ if (ih) console.log(` Invite host: ${ih}`);
1863
+ }
1864
+ if (statusData.warnings && statusData.warnings.length) {
1865
+ console.log('');
1866
+ for (const w of statusData.warnings) {
1867
+ console.log(` ⚠️ ${w}`);
1868
+ }
1869
+ }
1870
+ } catch (_) {
1871
+ // Dashboard status unavailable — that's fine, we already showed port
1872
+ }
1873
+ } else {
1874
+ console.log(' Server: ❌ Not running');
1875
+ console.log(' Start with: a2a server --port 3001');
1876
+ }
1877
+
1878
+ console.log(`\n Tip: a2a status <invite_url> to check a remote agent`);
1879
+ },
1880
+
1881
+ config: (args) => {
1882
+ const { A2AConfig } = require('../src/lib/config');
1883
+ const config = new A2AConfig();
1884
+
1885
+ const hostname = args.flags.hostname || args.flags.h;
1886
+ const port = args.flags.port || args.flags.p;
1887
+ const show = args.flags.show || args.flags.s || (!hostname && !port);
1888
+
1889
+ if (show) {
1890
+ const agent = config.getAgent();
1891
+ console.log('A2A Configuration:\n');
1892
+ console.log(` Hostname: ${agent.hostname || '(not set)'}`);
1893
+ console.log(` Name: ${agent.name || '(not set)'}`);
1894
+ console.log(` Description: ${agent.description || '(not set)'}`);
1895
+ const onboarding = config.getAll().onboarding || {};
1896
+ console.log(` Server port: ${onboarding.server_port || '(not running)'}`);
1897
+ console.log(` Onboarding step: ${onboarding.step || 'not started'}`);
1898
+ return;
1899
+ }
1900
+
1901
+ const updates = {};
1902
+ if (hostname) {
1903
+ // Remove port from hostname if it's :80 (default)
1904
+ const cleanHostname = hostname.replace(/:80$/, '');
1905
+ updates.hostname = cleanHostname;
1906
+ console.log(` Hostname updated to: ${cleanHostname}`);
1907
+ }
1908
+
1909
+ if (Object.keys(updates).length > 0) {
1910
+ config.setAgent(updates);
1911
+ console.log(' ✅ Configuration saved.');
1912
+ }
1913
+ },
1914
+
1915
+ server: (args) => {
1916
+ const explicitPort = args.flags.port || args.flags.p || process.env.PORT;
1917
+ if (explicitPort) {
1918
+ process.env.PORT = explicitPort;
1919
+ console.log(`Starting A2A server on port ${explicitPort}...`);
1920
+ } else {
1921
+ console.log('Starting A2A server (scanning for available port)...');
1922
+ }
1923
+ require('../src/server.js');
1924
+ },
1925
+
1926
+ // ==========================================================================
1927
+ // quickstart — full onboarding flow
1928
+ //
1929
+ // OBJECTIVE: Walk an installing agent (or human) through every step needed
1930
+ // to get A2A Calling running, in a single pass. The postinstall hook calls
1931
+ // this automatically, so `npm install -g a2acalling` completes the entire
1932
+ // setup without any follow-up commands.
1933
+ //
1934
+ // Every prompt auto-accepts its default when there is no TTY, so the full
1935
+ // flow completes unattended in non-interactive environments (agents).
1936
+ //
1937
+ // STEPS:
1938
+ // Step 1 — Port selection: scan for an available port and bind it.
1939
+ // Step 2 — Hostname detection: look up the external IP so remote agents
1940
+ // know where to reach this instance.
1941
+ // Step 3 — Server start: launch the A2A server as a detached process,
1942
+ // confirm it's listening, save config, and print a verify hint.
1943
+ // Step 4 — Disclosure prompt: output a full agent-readable prompt that
1944
+ // instructs the agent to scan its own workspace files, extract
1945
+ // tiered disclosure topics, and submit them back via
1946
+ // `a2a quickstart --submit '<json>'`.
1947
+ //
1948
+ // The disclosure prompt does NOT pre-scan files itself — it tells the agent
1949
+ // which files to look for (USER.md, SOUL.md, etc.) and lets the agent read
1950
+ // them with its own tools. This is intentional: the installer runs in a
1951
+ // subprocess where it has no access to the agent's file-reading capabilities.
1952
+ // ==========================================================================
1953
+ quickstart: async (args) => {
1954
+ const { A2AConfig } = require('../src/lib/config');
1955
+ const { isPortListening } = require('../src/lib/port-scanner');
1956
+ const { buildExtractionPrompt } = require('../src/lib/disclosure');
1957
+ const { getExternalIp } = require('../src/lib/external-ip');
1958
+
1959
+ const config = new A2AConfig();
1960
+ const interactive = isInteractiveShell();
1961
+
1962
+ // Handle `quickstart --submit '<json>'` — this is the agent calling back
1963
+ // after it has scanned its workspace and built the disclosure JSON.
1964
+ if (await handleDisclosureSubmit(args, 'quickstart')) {
1965
+ return;
1966
+ }
1967
+
1968
+ if (args.flags.force) {
1969
+ config.resetOnboarding();
1970
+ }
1971
+
1972
+ // Already onboarded — skip unless --force
1973
+ if (config.isOnboarded() && !args.flags.force) {
1974
+ console.log('\nOnboarding already complete. Use --force to re-run.\n');
1975
+ return;
1976
+ }
1977
+
1978
+ // Resume point: if the server is already running and we're waiting for the
1979
+ // agent to submit disclosure topics, skip straight to the disclosure prompt.
1980
+ // This happens when the agent re-runs quickstart after a previous partial run.
1981
+ let currentStep = 'not_started';
1982
+ try {
1983
+ const cfg = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8'));
1984
+ currentStep = cfg.onboarding?.step || 'not_started';
1985
+ } catch (e) {
1986
+ if (e.code !== 'ENOENT' && e.name !== 'SyntaxError') {
1987
+ console.error(` Warning: could not read config: ${e.message}`);
1988
+ }
1989
+ }
1990
+ if (currentStep === 'awaiting_disclosure' && !args.flags.force) {
1991
+ console.log('\nStep 1 already complete. Server is running.\n');
1992
+ console.log('Step 2 of 4: Configure disclosure topics\n');
1993
+ console.log(buildExtractionPrompt());
1994
+ console.log('\n Read your workspace files, extract topics, and present to your owner for review.');
1995
+ console.log(" Then submit with: a2a quickstart --submit '<json>'\n");
1996
+ return;
1997
+ }
1998
+
1999
+ printStepHeader('🤝 A2A Calling — First-Time Setup');
2000
+
2001
+ // Interactive: ask for confirmation. Non-interactive: auto-accepts (Y).
2002
+ const continueSetup = await promptYesNo('Continue with setup? [Y/n] ');
2003
+ if (!continueSetup) {
2004
+ console.log('\nSetup cancelled.\n');
2005
+ return;
2006
+ }
2007
+
2008
+ // ── Step 1: Port selection ───────────────────────────────────────────
2009
+ // Port 80 is strongly preferred (no firewall config needed for external access).
2010
+ // If port 80 is available and bindable, use it. Otherwise fall back to 3001-3020.
2011
+ printSection('Port Configuration');
2012
+ const preferredPort = parsePort(args.flags.port || args.flags.p, null);
2013
+ const candidates = await inspectPorts(preferredPort);
2014
+ const availableCandidates = candidates.filter(c => c.available);
2015
+
2016
+ // Strongly prefer port 80 if available
2017
+ const port80Candidate = candidates.find(c => c.port === 80);
2018
+ const port80Available = port80Candidate && port80Candidate.available;
2019
+
2020
+ let recommendedPort;
2021
+ if (port80Available) {
2022
+ recommendedPort = 80;
2023
+ } else if (availableCandidates.length) {
2024
+ recommendedPort = availableCandidates[0].port;
2025
+ } else {
2026
+ recommendedPort = null;
2027
+ }
2028
+
2029
+ if (!recommendedPort) {
2030
+ console.error(' Could not find a bindable port in the scan range.');
2031
+ console.error(' Re-run with --port <number> after freeing one of these ports.\n');
2032
+ if (interactive) {
2033
+ console.log(' Ports scanned:');
2034
+ summarizePortResults(candidates).forEach(line => console.log(` ${line}`));
2035
+ }
2036
+ process.exit(1);
2037
+ }
2038
+
2039
+ let serverPort = recommendedPort;
2040
+ let proxyStrategy = false; // true if user chose reverse proxy option
2041
+
2042
+ if (port80Available) {
2043
+ // Port 80 available — simple confirm
2044
+ console.log(' Port 80 is available — using it for easiest external access.');
2045
+ const portPrompt = `Use port 80? [Y/n]: `;
2046
+ const portChoice = await promptText(portPrompt, 'y');
2047
+
2048
+ if (!interactive) {
2049
+ serverPort = 80;
2050
+ } else if (!['', 'y', 'Y', 'yes', 'YES', 'ye'].includes(String(portChoice).trim())) {
2051
+ if (/^(n|no|custom|c)$/i.test(String(portChoice).trim())) {
2052
+ let customPort = null;
2053
+ while (customPort === null) {
2054
+ const raw = await promptText('Enter a custom port number: ', String(recommendedPort));
2055
+ const parsed = parsePort(raw, null);
2056
+ if (!parsed) {
2057
+ console.log(' Invalid port. Enter a value between 1 and 65535.');
2058
+ continue;
2059
+ }
2060
+ const checked = await (async () => {
2061
+ const scan = await inspectPorts(parsed);
2062
+ return scan[0];
2063
+ })();
2064
+ if (!checked.available) {
2065
+ console.log(` Port ${parsed} is unavailable (${checked.code || 'in use'}).`);
2066
+ continue;
2067
+ }
2068
+ customPort = parsed;
2069
+ }
2070
+ serverPort = customPort;
2071
+ } else {
2072
+ const parsed = parsePort(portChoice, null);
2073
+ if (parsed) {
2074
+ const checked = await (async () => {
2075
+ const scan = await inspectPorts(parsed);
2076
+ return scan[0];
2077
+ })();
2078
+ if (!checked.available) {
2079
+ console.log(` Port ${parsed} is unavailable (${checked.code || 'in use'}).`);
2080
+ } else {
2081
+ serverPort = parsed;
2082
+ }
2083
+ }
2084
+ }
2085
+ }
2086
+ } else {
2087
+ // Port 80 NOT available — show the fallback strategy prompt
2088
+ const fallback = await promptPortFallbackStrategy(recommendedPort, interactive);
2089
+
2090
+ if (fallback.strategy === 'kill') {
2091
+ const confirmKill = await promptYesNo(` Kill ${(fallback.processInfo && fallback.processInfo.name) || 'process'} (PID ${(fallback.processInfo && fallback.processInfo.pid) || '?'})? (y/N) `);
2092
+ if (confirmKill) {
2093
+ const killed = await killPortProcess(fallback.processInfo);
2094
+ if (killed) {
2095
+ serverPort = 80;
2096
+ } else {
2097
+ console.log(`\n Falling back to port ${recommendedPort}.`);
2098
+ console.log(' You can set up a reverse proxy after setup completes.\n');
2099
+ serverPort = recommendedPort;
2100
+ }
2101
+ } else {
2102
+ console.log(` Skipped. Using port ${recommendedPort}.\n`);
2103
+ serverPort = recommendedPort;
2104
+ }
2105
+ } else if (fallback.strategy === 'proxy') {
2106
+ serverPort = fallback.port;
2107
+ proxyStrategy = true;
2108
+ } else {
2109
+ serverPort = fallback.port;
2110
+ }
2111
+ }
2112
+
2113
+ // ── Step 2: Hostname detection ───────────────────────────────────────
2114
+ // Look up the machine's external IP so invite URLs point to a routable
2115
+ // address. Non-interactive: auto-uses the detected IP. Interactive: lets
2116
+ // the user choose IP, domain, or skip.
2117
+ printSection('Hostname Configuration');
2118
+ const ipResult = await getExternalIp();
2119
+ const externalIp = ipResult.ip || null;
2120
+ let publicHost = `localhost:${serverPort}`;
2121
+
2122
+ if (externalIp) {
2123
+ const detectedHost = serverPort === 80 ? externalIp : `${externalIp}:${serverPort}`;
2124
+ console.log(` Detected external IP: ${detectedHost}`);
2125
+ if (interactive) {
2126
+ const hostChoiceRaw = await promptText(
2127
+ 'How should other agents reach you?\n'
2128
+ + ' 1. Use IP directly\n'
2129
+ + ' 2. Enter a domain name\n'
2130
+ + ' 3. Skip (configure later)\n'
2131
+ + 'Choice [1/2/3]: ',
2132
+ '1'
2133
+ );
2134
+ const hostChoice = String(hostChoiceRaw || '').trim();
2135
+ if (hostChoice === '2') {
2136
+ const manualHost = await promptText('Enter your public hostname: ', '');
2137
+ if (manualHost) publicHost = String(manualHost).trim();
2138
+ } else if (hostChoice === '3') {
2139
+ publicHost = process.env.A2A_HOSTNAME || `localhost:${serverPort}`;
2140
+ } else {
2141
+ publicHost = detectedHost;
2142
+ }
2143
+ } else {
2144
+ publicHost = detectedHost;
2145
+ }
2146
+ } else if (interactive) {
2147
+ const hostChoiceRaw = await promptText(
2148
+ 'External IP unavailable.\nHow should other agents reach you?\n'
2149
+ + ' 1. Enter a domain name\n'
2150
+ + ' 2. Skip (use localhost)\n'
2151
+ + 'Choice [1/2]: ',
2152
+ '2'
2153
+ );
2154
+ const hostChoice = String(hostChoiceRaw || '').trim();
2155
+ if (hostChoice === '1') {
2156
+ const manualHost = await promptText('Enter your public hostname: ', '');
2157
+ if (manualHost) publicHost = String(manualHost).trim();
2158
+ }
2159
+ } else if (ipResult.error) {
2160
+ console.log(` External IP lookup failed: ${ipResult.error}`);
2161
+ }
2162
+
2163
+ // ── Step 3: Server start ─────────────────────────────────────────────
2164
+ // Launch the A2A Express server as a detached background process, wait
2165
+ // for it to bind, then save the config with the server PID and port.
2166
+ // Non-interactive: auto-starts. Interactive: asks for confirmation.
2167
+ // Also prints a one-line networking hint (reverse proxy or firewall)
2168
+ // and a curl command the agent can use to verify external reachability.
2169
+ printSection('Starting Server');
2170
+ console.log(' Configuration summary:');
2171
+ console.log(` Port: ${serverPort}`);
2172
+ console.log(` Public host: ${publicHost}`);
2173
+
2174
+ const startServer = await promptYesNo('Start the A2A server now? [Y/n] ');
2175
+ if (!startServer) {
2176
+ console.log('\nServer not started. Run with:\n a2a server --port <port> --hostname <host>\n');
2177
+ return;
2178
+ }
2179
+
2180
+ // Pre-start cleanup: kill any existing a2a server from a previous run
2181
+ try {
2182
+ const { killExistingServer } = require('../src/lib/pid-file');
2183
+ const cleanup = killExistingServer();
2184
+ if (cleanup.killed) {
2185
+ console.log(` Stopped previous server (PID ${cleanup.pid}).`);
2186
+ // Brief pause to let the port free up
2187
+ await new Promise(r => setTimeout(r, 500));
2188
+ }
2189
+ } catch (e) {
2190
+ // Best effort — continue with startup
2191
+ }
2192
+
2193
+ const isAlreadyListening = await isPortListening(serverPort, '127.0.0.1', { timeoutMs: 250 });
2194
+ let serverPid = null;
2195
+ if (!isAlreadyListening.listening) {
2196
+ const serverScript = path.join(__dirname, '../src/server.js');
2197
+ const child = spawn(process.execPath, [serverScript], {
2198
+ env: { ...process.env, PORT: String(serverPort) },
2199
+ detached: true,
2200
+ stdio: 'ignore'
2201
+ });
2202
+ serverPid = child.pid;
2203
+ child.unref();
2204
+ } else {
2205
+ console.log(' Existing server detected on this port.');
2206
+ }
2207
+
2208
+ async function waitForServer(port) {
2209
+ for (let i = 0; i < 18; i++) {
2210
+ const listening = await isPortListening(port, '127.0.0.1', { timeoutMs: 250 });
2211
+ if (listening.listening) return true;
2212
+ await new Promise(r => setTimeout(r, 250));
2213
+ }
2214
+ return false;
2215
+ }
2216
+
2217
+ const serverUp = await waitForServer(serverPort);
2218
+ if (!serverUp) {
2219
+ console.log(' Server failed to start. Check logs and retry:');
2220
+ console.log(` PORT=${serverPort} node ${path.join(__dirname, '../src/server.js')}`);
2221
+ process.exit(1);
2222
+ }
2223
+
2224
+ if (serverPid) {
2225
+ console.log(' Server started.');
2226
+ const existingPids = (config.getOnboarding().server_pids || []).filter(p => {
2227
+ try { process.kill(p, 0); return true; } catch (e) { return false; }
2228
+ });
2229
+ if (!existingPids.includes(serverPid)) existingPids.push(serverPid);
2230
+ config.setOnboarding({
2231
+ server_pid: serverPid,
2232
+ server_pids: existingPids,
2233
+ server_port: serverPort
2234
+ });
2235
+ } else {
2236
+ console.log(' Using existing server.');
2237
+ // Persist detected server port even when reusing an already-running process.
2238
+ // Native app discovery depends on onboarding.server_port as a primary hint.
2239
+ config.setOnboarding({ server_port: serverPort });
2240
+ }
2241
+ console.log(' ✅ A2A server is running');
2242
+
2243
+ if (externalIp) {
2244
+ if (serverPort === 80) {
2245
+ // Port 80 — optimal setup, no extra config needed
2246
+ console.log(`\n ✅ Running on port 80 — external agents can reach you directly.`);
2247
+ console.log(` Invite hostname: ${externalIp}`);
2248
+ publicHost = externalIp;
2249
+ } else if (proxyStrategy) {
2250
+ // User chose to set up a reverse proxy
2251
+ const proxy = generateProxyConfig(serverPort);
2252
+
2253
+ console.log(`\n ━━━ Reverse Proxy Configuration ━━━`);
2254
+ console.log(`\n A2A server running on port ${serverPort}. Configure your web server`);
2255
+ console.log(` to proxy port 80 → ${serverPort} so invite URLs work without a port number.\n`);
2256
+
2257
+ if (proxy.hasNginx) {
2258
+ console.log(' ┌─────────────────────────────────────────────────────────────────┐');
2259
+ console.log(' │ nginx — add inside your server {} block │');
2260
+ console.log(' │ File: /etc/nginx/sites-available/default │');
2261
+ console.log(' └─────────────────────────────────────────────────────────────────┘');
2262
+ console.log('');
2263
+ proxy.nginxConfig.split('\n').forEach(line => console.log(` ${line}`));
2264
+ console.log('');
2265
+ console.log(' To apply:');
2266
+ console.log(' 1. sudo nano /etc/nginx/sites-available/default');
2267
+ console.log(' 2. Add the config above inside your server { } block');
2268
+ console.log(' 3. sudo nginx -t');
2269
+ console.log(' 4. sudo systemctl reload nginx');
2270
+ }
2271
+
2272
+ if (proxy.hasCaddy) {
2273
+ console.log('');
2274
+ console.log(' ┌─────────────────────────────────────────────────────────────────┐');
2275
+ console.log(' │ Caddy config │');
2276
+ console.log(' └─────────────────────────────────────────────────────────────────┘');
2277
+ console.log('');
2278
+ proxy.caddyConfig.split('\n').forEach(line => console.log(` ${line}`));
2279
+ }
2280
+
2281
+ if (!proxy.hasNginx && !proxy.hasCaddy) {
2282
+ console.log(' No nginx or Caddy detected. Install one:');
2283
+ console.log(' sudo apt install nginx # Debian/Ubuntu');
2284
+ console.log(' sudo yum install nginx # RHEL/CentOS');
2285
+ console.log('');
2286
+ console.log(' Then add this proxy config:');
2287
+ proxy.nginxConfig.split('\n').forEach(line => console.log(` ${line}`));
2288
+ }
2289
+
2290
+ // With reverse proxy, invite URLs use port 80 (no port in URL)
2291
+ console.log(`\n After applying, invite hostname will be: ${externalIp} (no port needed)`);
2292
+ publicHost = externalIp;
2293
+ } else {
2294
+ // User chose 'continue' on non-standard port — brief reminder
2295
+ console.log(`\n ⚠ Running on port ${serverPort} (non-standard).`);
2296
+ console.log(` Invite hostname: ${publicHost}`);
2297
+ console.log('');
2298
+ console.log(' ⚠️ Remote agents using your invite URL will try port 80 by default.');
2299
+ console.log(' Without a reverse proxy, inbound calls on port 80 will fail silently.');
2300
+ console.log(`\n To set up a reverse proxy later:`);
2301
+ console.log(` a2a config --hostname ${externalIp}`);
2302
+ console.log(` Then configure nginx/caddy to proxy port 80 → ${serverPort}.`);
2303
+ }
2304
+
2305
+ const verifyUrl = `http://${publicHost}/api/a2a/ping`;
2306
+ console.log(`\n Verify: curl -s ${verifyUrl}`);
2307
+
2308
+ // Fix 6: Actually run the connectivity check
2309
+ const http = require('http');
2310
+ const verifyOk = await new Promise(resolve => {
2311
+ const req = http.request({
2312
+ hostname: '127.0.0.1',
2313
+ port: serverPort,
2314
+ path: '/api/a2a/ping',
2315
+ method: 'GET',
2316
+ timeout: 2000
2317
+ }, (res) => {
2318
+ res.resume();
2319
+ resolve(res.statusCode === 200);
2320
+ });
2321
+ req.on('error', () => resolve(false));
2322
+ req.on('timeout', () => { req.destroy(); resolve(false); });
2323
+ req.end();
2324
+ });
2325
+
2326
+ if (verifyOk) {
2327
+ console.log(' ✅ Local connectivity verified');
2328
+ } else {
2329
+ console.log(' ⚠️ Local server check failed — server may still be starting');
2330
+ }
2331
+
2332
+ // Fix 7: Surface invite-host warnings during quickstart
2333
+ try {
2334
+ const { resolveInviteHost } = require('../src/lib/invite-host');
2335
+ const resolved = await resolveInviteHost({
2336
+ hostname: publicHost,
2337
+ port: serverPort
2338
+ });
2339
+ if (resolved.warnings && resolved.warnings.length) {
2340
+ console.log('\n ━━━ Network Warnings ━━━');
2341
+ for (const w of resolved.warnings) {
2342
+ console.warn(` ⚠️ ${w}`);
2343
+ }
2344
+ }
2345
+ } catch (_) {}
2346
+ }
2347
+
2348
+ // A2A-52: Generate Ed25519 keypair for cryptographic identity (skip if already exists)
2349
+ const existingKeypair = config.getKeypair();
2350
+ if (!existingKeypair) {
2351
+ const { generateKeypair, fingerprint: fpFunc } = require('../src/lib/crypto');
2352
+ const keypair = generateKeypair();
2353
+ config.setKeypair(keypair.privateKey, keypair.publicKey);
2354
+ const fp = fpFunc(keypair.publicKey);
2355
+ console.log(`\n 🔑 Ed25519 identity generated`);
2356
+ console.log(` Fingerprint: ${fp}`);
2357
+ } else {
2358
+ const { fingerprint: fpFunc } = require('../src/lib/crypto');
2359
+ console.log(`\n 🔑 Ed25519 identity exists (not overwritten)`);
2360
+ console.log(` Fingerprint: ${fpFunc(existingKeypair.publicKey)}`);
2361
+ }
2362
+
2363
+ // Save server config and advance onboarding state to awaiting_disclosure.
2364
+ config.setAgent({ hostname: publicHost });
2365
+ config.setOnboarding({ step: 'awaiting_disclosure' });
2366
+
2367
+ // ── Step 4: Disclosure prompt ────────────────────────────────────────
2368
+ // Output a full agent-readable prompt that tells the agent to:
2369
+ // 1. Scan its own workspace for USER.md, SOUL.md, etc.
2370
+ // 2. Extract tiered disclosure topics from those files
2371
+ // 3. Build the required JSON structure
2372
+ // 4. Submit it back via `a2a quickstart --submit '<json>'`
2373
+ //
2374
+ // IMPORTANT: We do NOT pre-scan files here. The installer runs in a
2375
+ // subprocess and has no access to the agent's file-reading tools. The
2376
+ // prompt lists which files to look for and the agent reads them itself.
2377
+ printSection('Disclosure Topic Extraction');
2378
+ console.log('Step 2 of 4: Configure disclosure topics\n');
2379
+ console.log(buildExtractionPrompt());
2380
+ console.log('\n Read your workspace files, extract topics, and present to your owner for review.');
2381
+ console.log(" Then submit with: a2a quickstart --submit '<json>'\n");
2382
+ },
2383
+
2384
+
2385
+ install: () => {
2386
+ require('../scripts/install-openclaw.js');
2387
+ },
2388
+
2389
+ setup: () => {
2390
+ require('../scripts/install-openclaw.js');
2391
+ },
2392
+
2393
+ app: (args) => {
2394
+ const action = String(args._[1] || 'status').trim().toLowerCase();
2395
+ const force = Boolean(args.flags.force || args.flags.f);
2396
+ const quiet = Boolean(args.flags.quiet || args.flags.q);
2397
+ const pkgVersion = require('../package.json').version;
2398
+
2399
+ if (action === 'status') {
2400
+ const installedAppPath = findNativeApp();
2401
+ const preferredPath = getNativeAppPaths().appPath;
2402
+ const version = installedAppPath ? parseInstalledNativeAppVersion(installedAppPath) : null;
2403
+ console.log('A2A Native App Status\n');
2404
+ console.log(` Platform: ${os.platform()}`);
2405
+ console.log(` CLI version: ${pkgVersion}`);
2406
+ if (os.platform() !== 'darwin') {
2407
+ console.log(' Native app: Not supported on this platform');
2408
+ return;
2409
+ }
2410
+ console.log(` Installed: ${installedAppPath ? 'yes' : 'no'}`);
2411
+ console.log(` App path: ${installedAppPath || preferredPath}`);
2412
+ console.log(` App version: ${version || '(unknown)'}`);
2413
+ if (!installedAppPath) {
2414
+ console.log('\nInstall with: a2a app install');
2415
+ }
2416
+ return;
2417
+ }
2418
+
2419
+ if (action === 'install') {
2420
+ if (os.platform() === 'darwin' && !force && !isOnboarded()) {
2421
+ console.error('Onboarding not complete. Run `a2a quickstart` first, then install the app.');
2422
+ console.error('Use `a2a app install --force` to bypass this check.');
2423
+ process.exit(1);
2424
+ }
2425
+ const result = installNativeMacApp({ force, quiet });
2426
+ if (result.skipped === 'not_macos') {
2427
+ console.error('Native app install is only available on macOS.');
2428
+ process.exit(1);
2429
+ }
2430
+ if (!result.success) {
2431
+ console.error(`Native app install failed: ${result.error || 'unknown error'}`);
2432
+ process.exit(1);
2433
+ }
2434
+ if (result.reason === 'already_current') {
2435
+ console.log(`Native app already installed at current version (${result.version}).`);
2436
+ console.log(`Path: ${result.appPath}`);
2437
+ return;
2438
+ }
2439
+ console.log(`Native app installed (v${result.version}).`);
2440
+ console.log(`Path: ${result.appPath}`);
2441
+ return;
2442
+ }
2443
+
2444
+ if (action === 'uninstall') {
2445
+ const result = uninstallNativeMacApp();
2446
+ if (result.skipped === 'not_macos') {
2447
+ console.error('Native app uninstall is only available on macOS.');
2448
+ process.exit(1);
2449
+ }
2450
+ if (!result.success) {
2451
+ console.error(`Native app uninstall failed: ${result.error || 'unknown error'}`);
2452
+ process.exit(1);
2453
+ }
2454
+ if (!result.removed) {
2455
+ console.log('Native app is not installed.');
2456
+ return;
2457
+ }
2458
+ console.log(`Native app removed: ${result.appPath}`);
2459
+ return;
2460
+ }
2461
+
2462
+ console.error('Usage: a2a app <status|install|uninstall> [--force] [--quiet]');
2463
+ process.exit(1);
2464
+ },
2465
+
2466
+ uninstall: async (args) => {
2467
+ const fs = require('fs');
2468
+ const path = require('path');
2469
+ const { spawnSync } = require('child_process');
2470
+
2471
+ const keepConfig = Boolean(args.flags['keep-config'] || args.flags.keepConfig);
2472
+ const force = Boolean(args.flags.force || args.flags.f);
2473
+
2474
+ const configDir = process.env.A2A_CONFIG_DIR ||
2475
+ process.env.OPENCLAW_CONFIG_DIR ||
2476
+ path.join(process.env.HOME || '/tmp', '.config', 'openclaw');
2477
+
2478
+ const configFile = path.join(configDir, 'a2a-config.json');
2479
+ const disclosureFile = path.join(configDir, 'a2a-disclosure.json');
2480
+ const tokensFile = path.join(configDir, 'a2a-tokens.json');
2481
+ const tokenStoreFile = path.join(configDir, 'a2a.json');
2482
+ const externalIpFile = path.join(configDir, 'a2a-external-ip.json');
2483
+ const dbFile = path.join(configDir, 'a2a-conversations.db');
2484
+ const logsDbFile = path.join(configDir, 'a2a-logs.db');
2485
+ const callbookDbFile = path.join(configDir, 'a2a-callbook.db');
2486
+
2487
+ console.log(`\n🗑️ A2A Uninstall`);
2488
+ console.log('─────────────────\n');
2489
+
2490
+ if (!keepConfig && !force) {
2491
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
2492
+ console.error('Refusing to prompt without a TTY. Re-run with --force to confirm uninstall.');
2493
+ process.exit(1);
2494
+ }
2495
+
2496
+ const existing = [configFile, disclosureFile, tokensFile, tokenStoreFile, externalIpFile, dbFile, logsDbFile, callbookDbFile].filter(f => fs.existsSync(f));
2497
+ const list = existing.length ? existing.map(f => ` - ${f}`).join('\n') : ' (no local config/database files found)';
2498
+ const ok = await promptYesNo(
2499
+ `This will stop the pm2 process "a2a" and delete:\n${list}\nProceed? (y/N) `
2500
+ );
2501
+ if (!ok) {
2502
+ console.log('\nCancelled.\n');
2503
+ return;
2504
+ }
2505
+ }
2506
+
2507
+ function pm2Exists() {
2508
+ const res = spawnSync('pm2', ['--version'], { stdio: 'ignore', timeout: 4000 });
2509
+ if (res.error && res.error.code === 'ENOENT') return false;
2510
+ return res.status === 0;
2511
+ }
2512
+
2513
+ function pm2HasProcess(name) {
2514
+ const res = spawnSync('pm2', ['describe', name], { encoding: 'utf8', timeout: 6000 });
2515
+ if (res.error && res.error.code === 'ENOENT') return false;
2516
+ return res.status === 0;
2517
+ }
2518
+
2519
+ function pm2StopAndDelete(name) {
2520
+ if (!pm2Exists()) return { ok: true, skipped: true };
2521
+ if (!pm2HasProcess(name)) return { ok: true, skipped: true };
2522
+
2523
+ const stop = spawnSync('pm2', ['stop', name], { encoding: 'utf8', timeout: 8000 });
2524
+ if (stop.status !== 0) {
2525
+ const msg = (stop.stderr || stop.stdout || '').trim();
2526
+ return { ok: false, error: msg || 'pm2 stop failed' };
2527
+ }
2528
+
2529
+ const del = spawnSync('pm2', ['delete', name], { encoding: 'utf8', timeout: 8000 });
2530
+ if (del.status !== 0) {
2531
+ const msg = (del.stderr || del.stdout || '').trim();
2532
+ return { ok: false, error: msg || 'pm2 delete failed' };
2533
+ }
2534
+
2535
+ return { ok: true };
2536
+ }
2537
+
2538
+ function rmFileSafe(filePath) {
2539
+ try {
2540
+ fs.rmSync(filePath, { force: true });
2541
+ return { ok: true };
2542
+ } catch (err) {
2543
+ return { ok: false, error: err.message };
2544
+ }
2545
+ }
2546
+
2547
+ // Check if a TCP port is currently occupied (async, fast)
2548
+ function isPortOccupied(port) {
2549
+ if (!port) return false;
2550
+ const net = require('net');
2551
+ return new Promise((resolve) => {
2552
+ const socket = net.connect({ host: '127.0.0.1', port });
2553
+ let settled = false;
2554
+ const finish = (result) => {
2555
+ if (settled) return;
2556
+ settled = true;
2557
+ try { socket.destroy(); } catch (e) {}
2558
+ resolve(result);
2559
+ };
2560
+ socket.setTimeout(500, () => finish(false));
2561
+ socket.once('connect', () => finish(true));
2562
+ socket.once('error', () => finish(false));
2563
+ });
2564
+ }
2565
+
2566
+ // Find PID listening on a given port by parsing /proc/net/tcp6 (Linux)
2567
+ function findPidOnPort(port) {
2568
+ try {
2569
+ // Try fuser first (most reliable)
2570
+ const fuserResult = spawnSync('fuser', [`${port}/tcp`], {
2571
+ encoding: 'utf8', timeout: 3000, stdio: ['pipe', 'pipe', 'pipe']
2572
+ });
2573
+ if (fuserResult.status === 0 && fuserResult.stdout) {
2574
+ const pids = fuserResult.stdout.trim().split(/\s+/).map(Number).filter(p => p > 0);
2575
+ if (pids.length > 0) return pids;
2576
+ }
2577
+ } catch (e) { /* fuser not available, fall through */ }
2578
+
2579
+ try {
2580
+ // Fallback: parse /proc/net/tcp and /proc/net/tcp6
2581
+ const portHex = port.toString(16).toUpperCase().padStart(4, '0');
2582
+ const pids = [];
2583
+ for (const proto of ['/proc/net/tcp', '/proc/net/tcp6']) {
2584
+ let content;
2585
+ try { content = fs.readFileSync(proto, 'utf8'); } catch (e) { continue; }
2586
+ const lines = content.split('\n');
2587
+ for (const line of lines) {
2588
+ const parts = line.trim().split(/\s+/);
2589
+ if (parts.length < 10) continue;
2590
+ const localAddr = parts[1]; // e.g., 00000000:1F90
2591
+ const localPort = localAddr.split(':')[1];
2592
+ if (localPort && localPort.toUpperCase() === portHex) {
2593
+ const inode = parts[9];
2594
+ // Search /proc/*/fd/* for socket inodes
2595
+ try {
2596
+ const procDirs = fs.readdirSync('/proc').filter(d => /^\d+$/.test(d));
2597
+ for (const pid of procDirs) {
2598
+ try {
2599
+ const fdDir = `/proc/${pid}/fd`;
2600
+ const fds = fs.readdirSync(fdDir);
2601
+ for (const fd of fds) {
2602
+ try {
2603
+ const link = fs.readlinkSync(`${fdDir}/${fd}`);
2604
+ if (link === `socket:[${inode}]`) {
2605
+ pids.push(Number(pid));
2606
+ }
2607
+ } catch (e) {}
2608
+ }
2609
+ } catch (e) {}
2610
+ }
2611
+ } catch (e) {}
2612
+ }
2613
+ }
2614
+ }
2615
+ if (pids.length > 0) return [...new Set(pids)];
2616
+ } catch (e) { /* /proc parsing failed */ }
2617
+
2618
+ return [];
2619
+ }
2620
+
2621
+ // Kill a specific PID with SIGTERM, wait, then SIGKILL if needed
2622
+ function killPidSync(pid) {
2623
+ try {
2624
+ process.kill(pid, 0); // existence check
2625
+ } catch (e) {
2626
+ return { ok: true, skipped: true };
2627
+ }
2628
+
2629
+ process.kill(pid, 'SIGTERM');
2630
+ const start = Date.now();
2631
+ while (Date.now() - start < 3000) {
2632
+ try {
2633
+ process.kill(pid, 0);
2634
+ spawnSync('sleep', ['0.1'], { timeout: 500 });
2635
+ } catch (e) {
2636
+ return { ok: true, pid };
2637
+ }
2638
+ }
2639
+
2640
+ // Still alive — force kill
2641
+ try {
2642
+ process.kill(pid, 'SIGKILL');
2643
+ // Brief wait for SIGKILL to take effect
2644
+ spawnSync('sleep', ['0.2'], { timeout: 500 });
2645
+ try {
2646
+ process.kill(pid, 0);
2647
+ return { ok: false, pid, error: `PID ${pid} survived SIGKILL` };
2648
+ } catch (e) {
2649
+ return { ok: true, pid, forced: true };
2650
+ }
2651
+ } catch (e) {
2652
+ return { ok: true, pid };
2653
+ }
2654
+ }
2655
+
2656
+ // Kill server by PID from config and PID file (detached process started by quickstart)
2657
+ // Then verify the port is actually freed; if not, find and kill whatever holds it.
2658
+ async function killServerPid() {
2659
+ let pid, serverPort, serverPids = [];
2660
+ try {
2661
+ const { A2AConfig } = require('../src/lib/config');
2662
+ const cfg = new A2AConfig();
2663
+ const onboarding = cfg.getOnboarding();
2664
+ pid = onboarding.server_pid;
2665
+ serverPort = onboarding.server_port;
2666
+ serverPids = Array.isArray(onboarding.server_pids) ? onboarding.server_pids : [];
2667
+ } catch (err) {
2668
+ // Config read failed — not fatal, continue
2669
+ }
2670
+
2671
+ // Step 0: Try PID file first (most reliable source)
2672
+ try {
2673
+ const { readPidFile, removePidFile } = require('../src/lib/pid-file');
2674
+ const filePid = readPidFile();
2675
+ if (filePid) {
2676
+ killPidSync(filePid);
2677
+ removePidFile();
2678
+ // If config PID is the same, don't double-kill
2679
+ if (filePid === pid) pid = null;
2680
+ }
2681
+ } catch (e) {
2682
+ // pid-file module load failed — continue with config PID
2683
+ }
2684
+
2685
+ // Step 1: Try to kill all tracked PIDs from config
2686
+ const allPids = new Set();
2687
+ if (pid) allPids.add(pid);
2688
+ for (const p of serverPids) {
2689
+ if (typeof p === 'number' && p > 0) allPids.add(p);
2690
+ }
2691
+ for (const p of allPids) {
2692
+ killPidSync(p);
2693
+ }
2694
+
2695
+ // Step 2: Verify the port is freed
2696
+ if (serverPort) {
2697
+ const stillOccupied = await isPortOccupied(serverPort);
2698
+ if (stillOccupied) {
2699
+ // Port is still held — find and kill whatever is on it
2700
+ const pids = findPidOnPort(serverPort);
2701
+ let killedAny = false;
2702
+ for (const p of pids) {
2703
+ const result = killPidSync(p);
2704
+ if (result.ok && !result.skipped) killedAny = true;
2705
+ }
2706
+
2707
+ // Final check
2708
+ const stillUp = await isPortOccupied(serverPort);
2709
+ if (stillUp) {
2710
+ return { ok: false, pid, port: serverPort, error: `Port ${serverPort} is still occupied after kill attempts` };
2711
+ }
2712
+ return { ok: true, pid, port: serverPort, portKill: killedAny };
2713
+ }
2714
+ }
2715
+
2716
+ // Clean up PID file if it still exists
2717
+ try {
2718
+ const { removePidFile } = require('../src/lib/pid-file');
2719
+ removePidFile();
2720
+ } catch (e) {}
2721
+
2722
+ return { ok: true, pid, port: serverPort, skipped: !pid && allPids.size === 0 };
2723
+ }
2724
+
2725
+ process.stdout.write('Stopping server... ');
2726
+ const pidResult = await killServerPid();
2727
+ const stopped = pm2StopAndDelete('a2a');
2728
+ if (!pidResult.ok && !stopped.ok) {
2729
+ console.log('❌');
2730
+ console.error(` ${pidResult.error || stopped.error}`);
2731
+ process.exit(1);
2732
+ }
2733
+ if (!pidResult.ok) {
2734
+ console.log('⚠️');
2735
+ console.error(` Warning: ${pidResult.error}`);
2736
+ } else {
2737
+ console.log('✅');
2738
+ }
2739
+
2740
+ let configOk = true;
2741
+ let dbOk = true;
2742
+
2743
+ if (!keepConfig) {
2744
+ process.stdout.write('Removing config... ');
2745
+ const c1 = rmFileSafe(configFile);
2746
+ const c2 = rmFileSafe(disclosureFile);
2747
+ const c3 = rmFileSafe(tokensFile);
2748
+ const c4 = rmFileSafe(tokenStoreFile);
2749
+ const c5 = rmFileSafe(externalIpFile);
2750
+ configOk = Boolean(c1.ok && c2.ok && c3.ok && c4.ok && c5.ok);
2751
+ console.log(configOk ? '✅' : '❌');
2752
+ if (!configOk) {
2753
+ if (!c1.ok) console.error(` ${configFile}: ${c1.error}`);
2754
+ if (!c2.ok) console.error(` ${disclosureFile}: ${c2.error}`);
2755
+ if (!c3.ok) console.error(` ${tokensFile}: ${c3.error}`);
2756
+ if (!c4.ok) console.error(` ${tokenStoreFile}: ${c4.error}`);
2757
+ if (!c5.ok) console.error(` ${externalIpFile}: ${c5.error}`);
2758
+ }
2759
+
2760
+ process.stdout.write('Removing database... ');
2761
+ const d1 = rmFileSafe(dbFile);
2762
+ const d2 = rmFileSafe(logsDbFile);
2763
+ const d3 = rmFileSafe(callbookDbFile);
2764
+ dbOk = Boolean(d1.ok && d2.ok && d3.ok);
2765
+ console.log(dbOk ? '✅' : '❌');
2766
+ if (!dbOk) {
2767
+ if (!d1.ok) console.error(` ${dbFile}: ${d1.error}`);
2768
+ if (!d2.ok) console.error(` ${logsDbFile}: ${d2.error}`);
2769
+ if (!d3.ok) console.error(` ${callbookDbFile}: ${d3.error}`);
2770
+ }
2771
+
2772
+ if (!configOk || !dbOk) {
2773
+ process.exit(1);
2774
+ }
2775
+ } else {
2776
+ console.log('Removing config... ⏭️');
2777
+ console.log('Removing database... ⏭️');
2778
+ }
2779
+
2780
+ // ── Remove installed skill files using the shared cleanup module ──────
2781
+ //
2782
+ // The postinstall script writes .a2a-manifest.json listing every file it
2783
+ // installed. We delegate to the shared cleanupProjectFiles() function which
2784
+ // handles CLAUDE.md section removal, file deletion, and empty directory
2785
+ // cleanup. This is the same logic used by the npm preuninstall hook,
2786
+ // ensuring both uninstall paths behave identically.
2787
+ //
2788
+ // We check multiple candidate directories for the manifest because `a2a
2789
+ // uninstall` might be run from a different directory than the one where
2790
+ // the package was originally installed.
2791
+ const manifestCandidates = [
2792
+ process.env.INIT_CWD,
2793
+ process.cwd(),
2794
+ ].filter(Boolean);
2795
+ // Deduplicate paths (INIT_CWD and cwd may be identical)
2796
+ const uniqueDirs = [...new Set(manifestCandidates.map(d => path.resolve(d)))];
2797
+
2798
+ let projectCleaned = false;
2799
+ for (const candidateDir of uniqueDirs) {
2800
+ if (fs.existsSync(path.join(candidateDir, '.a2a-manifest.json'))) {
2801
+ process.stdout.write('Removing installed skill files... ');
2802
+ try {
2803
+ const { cleanupProjectFiles } = require('../scripts/cleanup');
2804
+ const cleanResult = cleanupProjectFiles(candidateDir);
2805
+ const hasErrors = cleanResult.errors.length > 0;
2806
+ console.log(hasErrors ? '⚠️' : '✅');
2807
+ if (cleanResult.removed.length > 0) {
2808
+ for (const f of cleanResult.removed) {
2809
+ console.log(` - ${f}`);
2810
+ }
2811
+ }
2812
+ if (cleanResult.preserved.length > 0) {
2813
+ for (const f of cleanResult.preserved) {
2814
+ console.log(` ~ ${f}`);
2815
+ }
2816
+ }
2817
+ if (hasErrors) {
2818
+ for (const e of cleanResult.errors) {
2819
+ console.error(` ! ${e}`);
2820
+ }
2821
+ }
2822
+ projectCleaned = true;
2823
+ } catch (err) {
2824
+ console.log('⚠️');
2825
+ console.error(` Cleanup error: ${err.message}`);
2826
+ }
2827
+ break; // Only clean up once — first manifest found wins
2828
+ }
2829
+ }
2830
+ if (!projectCleaned) {
2831
+ // No manifest found in any candidate directory. This is expected when
2832
+ // `a2a uninstall` is run after `npm uninstall` (preuninstall already cleaned).
2833
+ console.log('Removing installed skill files... ⏭️ (no manifest found)');
2834
+ }
2835
+
2836
+ // Remove native macOS app if present
2837
+ if (os.platform() === 'darwin') {
2838
+ const appCandidates = [
2839
+ path.join(os.homedir(), 'Applications', 'A2A Callbook.app'),
2840
+ '/Applications/A2A Callbook.app',
2841
+ ];
2842
+ for (const appPath of appCandidates) {
2843
+ if (fs.existsSync(appPath)) {
2844
+ try {
2845
+ fs.rmSync(appPath, { recursive: true, force: true });
2846
+ console.log(`Removed ${appPath}`);
2847
+ } catch (err) {
2848
+ console.log(`Could not remove ${appPath}: ${err.message}`);
2849
+ }
2850
+ }
2851
+ }
2852
+ }
2853
+
2854
+ console.log('\nTo complete removal:');
2855
+ console.log(' npm uninstall -g a2acalling\n');
2856
+ console.log(`Config preserved: ${keepConfig ? 'yes' : 'no'}`);
2857
+ console.log(`Location: ${configDir}`);
2858
+ },
2859
+
2860
+ update: async (args) => {
2861
+ const { execSync } = require('child_process');
2862
+ const path = require('path');
2863
+ const pkg = require('../package.json');
2864
+ const { A2AConfig } = require('../src/lib/config');
2865
+ const currentVersion = pkg.version;
2866
+ const checkOnly = args.flags.check || args.flags.c;
2867
+ const autoMode = args.flags.auto ? String(args.flags.auto).trim().toLowerCase() : null;
2868
+
2869
+ if (autoMode) {
2870
+ const config = new A2AConfig();
2871
+ if (autoMode === 'status') {
2872
+ const au = config.getAutoUpdate ? config.getAutoUpdate() : { enabled: true, intervalMs: 3600000, allowMajor: false };
2873
+ console.log('Auto-update configuration:\n');
2874
+ console.log(` Enabled: ${au.enabled ? 'yes' : 'no'}`);
2875
+ console.log(` Interval: ${Math.floor((au.intervalMs || 3600000) / 1000)}s`);
2876
+ console.log(` Allow major updates: ${au.allowMajor ? 'yes' : 'no'}`);
2877
+ console.log(` Last known good version: ${au.lastGoodVersion || '(none)'}`);
2878
+ return;
2879
+ }
2880
+ if (autoMode === 'on' || autoMode === 'off') {
2881
+ config.setAutoUpdate({ enabled: autoMode === 'on' });
2882
+ console.log(`Auto-update ${autoMode === 'on' ? 'enabled' : 'disabled'}.`);
2883
+ return;
2884
+ }
2885
+ console.error('Invalid --auto value. Use: on | off | status');
2886
+ process.exit(1);
2887
+ }
2888
+
2889
+ console.log(`\n📦 A2A Update\n${'─'.repeat(50)}\n`);
2890
+ console.log(` Installed: v${currentVersion}`);
2891
+
2892
+ // Detect install method
2893
+ const pkgRoot = path.resolve(__dirname, '..');
2894
+ const isGitRepo = require('fs').existsSync(path.join(pkgRoot, '.git'));
2895
+
2896
+ if (isGitRepo) {
2897
+ // Git clone — use git pull
2898
+ console.log(` Source: git (${pkgRoot})\n`);
2899
+
2900
+ if (checkOnly) {
2901
+ try {
2902
+ execSync('git fetch --quiet', { cwd: pkgRoot, stdio: 'pipe' });
2903
+ const behind = execSync('git rev-list HEAD..@{u} --count', { cwd: pkgRoot, encoding: 'utf8' }).trim();
2904
+ if (behind === '0') {
2905
+ console.log(' \u2705 Already up to date.\n');
2906
+ } else {
2907
+ console.log(` \u2b06\ufe0f ${behind} commit(s) behind. Run "a2a update" to pull.\n`);
2908
+ }
2909
+ } catch (e) {
2910
+ console.log(' \u26a0\ufe0f Could not check remote (no upstream or network error).\n');
2911
+ }
2912
+ return;
2913
+ }
2914
+
2915
+ console.log(' Pulling latest...');
2916
+ try {
2917
+ const output = execSync('git pull --ff-only 2>&1', { cwd: pkgRoot, encoding: 'utf8' });
2918
+ console.log(` ${output.trim()}\n`);
2919
+ } catch (e) {
2920
+ const stderr = e.stderr ? e.stderr.toString() : e.message;
2921
+ console.error(` \u274c Git pull failed: ${stderr.trim()}`);
2922
+ console.error(' Try: cd ' + pkgRoot + ' && git pull manually.\n');
2923
+ process.exit(1);
2924
+ }
2925
+
2926
+ // Re-install deps if package.json changed
2927
+ console.log(' Installing dependencies...');
2928
+ try {
2929
+ execSync('npm install --production 2>&1', { cwd: pkgRoot, encoding: 'utf8', timeout: 120000 });
2930
+ } catch (e) {
2931
+ console.warn(' \u26a0\ufe0f npm install had warnings (non-fatal).');
2932
+ }
2933
+ } else {
2934
+ // npm global install — use npm update
2935
+ console.log(' Source: npm global\n');
2936
+
2937
+ // Check latest version on npm
2938
+ let latestVersion;
2939
+ try {
2940
+ latestVersion = execSync('npm view a2acalling version 2>/dev/null', { encoding: 'utf8', timeout: 15000 }).trim();
2941
+ console.log(` Latest: v${latestVersion}`);
2942
+ } catch (e) {
2943
+ console.error(' \u274c Could not check npm registry. Check your network.\n');
2944
+ process.exit(1);
2945
+ }
2946
+
2947
+ if (latestVersion === currentVersion) {
2948
+ console.log('\n \u2705 Already up to date.\n');
2949
+ return;
2950
+ }
2951
+
2952
+ if (checkOnly) {
2953
+ console.log(`\n \u2b06\ufe0f Update available: v${currentVersion} \u2192 v${latestVersion}`);
2954
+ console.log(' Run "a2a update" to install.\n');
2955
+ return;
2956
+ }
2957
+
2958
+ console.log(`\n Updating v${currentVersion} \u2192 v${latestVersion}...`);
2959
+ try {
2960
+ execSync('npm install -g a2acalling@latest 2>&1', { encoding: 'utf8', timeout: 120000 });
2961
+ console.log(' \u2705 npm package updated.\n');
2962
+ } catch (e) {
2963
+ const stderr = e.stderr ? e.stderr.toString() : e.message;
2964
+ console.error(` \u274c npm update failed: ${stderr.trim()}`);
2965
+ console.error(' Try: npm install -g a2acalling@latest manually.\n');
2966
+ process.exit(1);
2967
+ }
2968
+ }
2969
+
2970
+ // Re-run install to sync SKILL.md and config
2971
+ console.log(' Syncing SKILL.md and config...');
2972
+ try {
2973
+ const installScript = path.join(pkgRoot, 'scripts', 'install-openclaw.js');
2974
+ execSync(`node "${installScript}" install 2>&1`, { encoding: 'utf8', timeout: 30000 });
2975
+ } catch (e) {
2976
+ console.warn(' \u26a0\ufe0f Post-update install sync had warnings (non-fatal).');
2977
+ }
2978
+
2979
+ // Show new version
2980
+ try {
2981
+ delete require.cache[require.resolve('../package.json')];
2982
+ const newPkg = require('../package.json');
2983
+ console.log(`\n \u2705 Updated to v${newPkg.version}\n`);
2984
+ } catch (e) {
2985
+ console.log('\n \u2705 Update complete.\n');
2986
+ }
2987
+ },
2988
+
2989
+ onboard: async (args) => {
2990
+ if (await handleDisclosureSubmit(args, 'onboard')) {
2991
+ return;
2992
+ }
2993
+
2994
+ // ── No --submit: same as quickstart ───────────────────────
2995
+ return commands.quickstart(args);
2996
+ },
2997
+
2998
+ skills: (args) => {
2999
+ const { installSkills, SKILL_FILES } = require('../scripts/install-skills');
3000
+ const check = args.flags.check || args.flags.c;
3001
+ const force = args.flags.force;
3002
+ const targetDir = process.cwd();
3003
+
3004
+ if (check) {
3005
+ console.log('A2A skills for this project:\n');
3006
+ for (const file of SKILL_FILES) {
3007
+ const destPath = path.join(targetDir, file.dest);
3008
+ const exists = fs.existsSync(destPath);
3009
+ const icon = exists ? ' \u2713' : ' \u2717';
3010
+ console.log(`${icon} ${file.dest}${exists ? ' (installed)' : ' (not installed)'}`);
3011
+ }
3012
+ console.log(`\nRun "a2a skills" to install missing files.`);
3013
+ return;
3014
+ }
3015
+
3016
+ const result = installSkills(targetDir, { force });
3017
+
3018
+ if (result.installed.length) {
3019
+ console.log(`\n Installed ${result.installed.length} A2A skill file(s):\n`);
3020
+ result.installed.forEach(f => console.log(` + ${f}`));
3021
+ }
3022
+ if (result.skipped.length) {
3023
+ console.log(`\n Skipped ${result.skipped.length} unchanged file(s)`);
3024
+ }
3025
+ if (result.errors.length) {
3026
+ console.error(`\n Errors:`);
3027
+ result.errors.forEach(e => console.error(` ! ${e.file}: ${e.error}`));
3028
+ }
3029
+
3030
+ if (result.installed.length === 0 && result.skipped.length > 0) {
3031
+ console.log('\n All skills already installed. Use --force to overwrite.\n');
3032
+ } else if (result.installed.length > 0) {
3033
+ console.log('\n Skills ready. In Claude Code, type /a2a- to see available commands.');
3034
+ console.log(' In Codex CLI, A2A instructions are in .codex/AGENTS.md\n');
3035
+ }
3036
+ },
3037
+
3038
+ version: () => {
3039
+ const pkg = require('../package.json');
3040
+ console.log(pkg.version);
3041
+ },
3042
+
3043
+ help: () => {
3044
+ console.log(`A2A Calling - Agent-to-Agent Communication
3045
+
3046
+ Usage: a2a <command> [options]
3047
+
3048
+ Commands:
3049
+ create Create an A2A token
3050
+ --name, -n Token/agent name
3051
+ --owner, -o Owner name (human behind the agent)
3052
+ --expires, -e Expiration (1h, 1d, 7d, 30d, never)
3053
+ --permissions, -p Tier (public, friends, family)
3054
+ --topics Custom topics (comma-separated, overrides tier defaults)
3055
+ --tools Custom tool allowlist (comma-separated, overrides tier defaults)
3056
+ --notify Owner notification (all, summary, none)
3057
+ --max-calls Maximum invocations (default: 100)
3058
+ --timeout-ms Per-token Claude turn timeout in milliseconds
3059
+ --link, -l Auto-link to contact name
3060
+
3061
+ list List active tokens
3062
+ revoke <id> Revoke a token
3063
+
3064
+ Contacts:
3065
+ contacts List all contacts (shows permission badges)
3066
+ contacts add <url> Add a contact
3067
+ --name, -n Agent name
3068
+ --owner, -o Owner name
3069
+ --server-name Server label (optional)
3070
+ --notes Notes about this contact
3071
+ --tags Comma-separated tags
3072
+ --link Link to token ID you gave them
3073
+ contacts show <n> Show contact details + linked token
3074
+ contacts edit <n> Edit contact metadata
3075
+ --server-name Server label (optional)
3076
+ contacts link <n> <tok> Link a token to a contact
3077
+ contacts ping <n> Ping contact, update status
3078
+ contacts rm <n> Remove contact
3079
+
3080
+ Permission badges: 🌐 public 🔧 friends ⚡ family
3081
+
3082
+ Conversations:
3083
+ conversations List all conversations
3084
+ --contact Filter by contact
3085
+ --status Filter by status (active, concluded, timeout)
3086
+ --limit Max results (default: 20)
3087
+ conversations show <id> Show conversation with messages
3088
+ --messages Number of recent messages (default: 20)
3089
+ conversations end <id> End and summarize conversation
3090
+
3091
+ Calling:
3092
+ call <contact|url> <msg> Call a contact (multi-turn by default)
3093
+ --single Single-turn call (one message, one response)
3094
+ --min-turns N Minimum turns before close (default: 8)
3095
+ --max-turns N Maximum turns (default: 25)
3096
+ ping <url> Check if agent is reachable
3097
+ status <url> Get A2A status
3098
+ gui Open the local dashboard GUI in a browser
3099
+ --tab, -t Optional: contacts|calls|logs|permissions|invites
3100
+ app Manage native macOS app
3101
+ status Show native app installation status (default)
3102
+ install Install/update native app from GitHub release
3103
+ --force, -f Reinstall/bypass onboarding guard
3104
+ --quiet, -q Suppress download/extract output
3105
+ uninstall Remove native app from ~/Applications
3106
+
3107
+ Server:
3108
+ server Start the A2A server
3109
+ --port, -p Port to listen on (default: 3001)
3110
+
3111
+ quickstart Set up A2A server and start onboarding
3112
+ --port, -p Preferred server port (default: 80, fallback: 3001+)
3113
+ --submit '<json>' Submit disclosure JSON (Step 3 of onboarding)
3114
+ --force Reset onboarding and re-run from scratch
3115
+
3116
+ onboard Submit disclosure topics or resume quickstart
3117
+ --submit '<json>' Submit disclosure JSON (Step 3 of onboarding)
3118
+ --name Agent name for invite generation
3119
+ --force Re-run even if already onboarded
3120
+
3121
+ update Update A2A to latest version (npm or git pull)
3122
+ --check, -c Check for updates without installing
3123
+ --auto Manage auto-update: on|off|status
3124
+
3125
+ install Install A2A for OpenClaw
3126
+ setup Auto setup (gateway-aware dashboard install)
3127
+ uninstall Stop server and remove local config/DB
3128
+ --keep-config Preserve config/DB (for reinstall)
3129
+ --force Skip confirmation prompt
3130
+ skills Install Claude Code + Codex CLI skills
3131
+ --check, -c Show what would be installed
3132
+ --force Overwrite existing files
3133
+ version Show installed package version
3134
+
3135
+ Examples:
3136
+ a2a create --name "bappybot" --owner "Benjamin Pollack" --expires 7d
3137
+ a2a create --name "custom" --topics "chat,calendar.read,email.read"
3138
+ a2a create --name "research" --tools "Read,Grep,Glob,WebSearch,WebFetch"
3139
+ a2a contacts add a2a://host/fed_xxx --name "Alice" --owner "Alice Chen"
3140
+ a2a contacts link Alice tok_abc123
3141
+ a2a call Alice "Hello!"
3142
+ a2a conversations show conv_abc123
3143
+ a2a app status
3144
+ a2a app install --force
3145
+ a2a server --port 3001
3146
+ `);
3147
+ }
3148
+ };
3149
+
3150
+ // Main
3151
+ const args = parseArgs(process.argv);
3152
+
3153
+ // Handle --version flag before command dispatch (standard CLI convention)
3154
+ if (args.flags.version || args.flags.v) {
3155
+ commands.version();
3156
+ process.exit(0);
3157
+ }
3158
+
3159
+ const command = args._[0] || 'help';
3160
+
3161
+ if (!commands[command]) {
3162
+ console.error(`Unknown command: ${command}`);
3163
+ console.log('Run "a2a help" for usage.');
3164
+ process.exit(1);
3165
+ }
3166
+
3167
+ // If onboarding is incomplete, enforceOnboarding runs quickstart inline
3168
+ // (verbose, full output) and returns a Promise. Otherwise returns undefined
3169
+ // and we proceed to the requested command.
3170
+ const onboardResult = enforceOnboarding(command);
3171
+ if (onboardResult instanceof Promise) {
3172
+ onboardResult.catch(err => {
3173
+ console.error(err.message);
3174
+ process.exit(1);
3175
+ });
3176
+ } else {
3177
+ const result = commands[command](args);
3178
+ if (result instanceof Promise) {
3179
+ result.catch(err => {
3180
+ console.error(err.message);
3181
+ process.exit(1);
3182
+ });
3183
+ }
3184
+ }