artemys 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (332) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +194 -146
  3. package/dist/cli/index.d.ts +1 -1
  4. package/dist/cli/index.d.ts.map +1 -1
  5. package/dist/cli/index.js +446 -379
  6. package/dist/cli/index.js.map +1 -1
  7. package/dist/coffeeshop/client.d.ts +158 -0
  8. package/dist/coffeeshop/client.d.ts.map +1 -0
  9. package/dist/coffeeshop/client.js +293 -0
  10. package/dist/coffeeshop/client.js.map +1 -0
  11. package/dist/coffeeshop/index.d.ts +2 -0
  12. package/dist/coffeeshop/index.d.ts.map +1 -0
  13. package/dist/coffeeshop/index.js +2 -0
  14. package/dist/coffeeshop/index.js.map +1 -0
  15. package/dist/discovery/agent-card.schema.d.ts +37 -109
  16. package/dist/discovery/agent-card.schema.d.ts.map +1 -1
  17. package/dist/discovery/discovery-query.schema.d.ts +6 -15
  18. package/dist/discovery/discovery-query.schema.d.ts.map +1 -1
  19. package/dist/discovery/index.d.ts +1 -1
  20. package/dist/discovery/index.d.ts.map +1 -1
  21. package/dist/discovery/index.js +1 -1
  22. package/dist/discovery/index.js.map +1 -1
  23. package/dist/discovery/intro-decision.schema.d.ts +9 -11
  24. package/dist/discovery/intro-decision.schema.d.ts.map +1 -1
  25. package/dist/discovery/intro-request.schema.d.ts +2 -14
  26. package/dist/discovery/intro-request.schema.d.ts.map +1 -1
  27. package/dist/discovery/session-bootstrap.schema.d.ts +86 -66
  28. package/dist/discovery/session-bootstrap.schema.d.ts.map +1 -1
  29. package/dist/discovery/session-bootstrap.schema.js +84 -8
  30. package/dist/discovery/session-bootstrap.schema.js.map +1 -1
  31. package/dist/mcp-server/index.d.ts +4 -0
  32. package/dist/mcp-server/index.d.ts.map +1 -0
  33. package/dist/mcp-server/index.js +4 -0
  34. package/dist/mcp-server/index.js.map +1 -0
  35. package/dist/mcp-server/persistence.d.ts +37 -0
  36. package/dist/mcp-server/persistence.d.ts.map +1 -0
  37. package/dist/mcp-server/persistence.js +309 -0
  38. package/dist/mcp-server/persistence.js.map +1 -0
  39. package/dist/mcp-server/resources.d.ts +20 -0
  40. package/dist/mcp-server/resources.d.ts.map +1 -0
  41. package/dist/mcp-server/resources.js +49 -0
  42. package/dist/mcp-server/resources.js.map +1 -0
  43. package/dist/mcp-server/server.d.ts +33 -0
  44. package/dist/mcp-server/server.d.ts.map +1 -0
  45. package/dist/mcp-server/server.js +220 -0
  46. package/dist/mcp-server/server.js.map +1 -0
  47. package/dist/mcp-server/state.d.ts +43 -0
  48. package/dist/mcp-server/state.d.ts.map +1 -0
  49. package/dist/mcp-server/state.js +111 -0
  50. package/dist/mcp-server/state.js.map +1 -0
  51. package/dist/mcp-server/tools/common.d.ts +225 -0
  52. package/dist/mcp-server/tools/common.d.ts.map +1 -0
  53. package/dist/mcp-server/tools/common.js +11 -0
  54. package/dist/mcp-server/tools/common.js.map +1 -0
  55. package/dist/mcp-server/tools/discovery.d.ts +3 -0
  56. package/dist/mcp-server/tools/discovery.d.ts.map +1 -0
  57. package/dist/mcp-server/tools/discovery.js +48 -0
  58. package/dist/mcp-server/tools/discovery.js.map +1 -0
  59. package/dist/mcp-server/tools/index.d.ts +4 -0
  60. package/dist/mcp-server/tools/index.d.ts.map +1 -0
  61. package/dist/mcp-server/tools/index.js +13 -0
  62. package/dist/mcp-server/tools/index.js.map +1 -0
  63. package/dist/mcp-server/tools/intro.d.ts +3 -0
  64. package/dist/mcp-server/tools/intro.d.ts.map +1 -0
  65. package/dist/mcp-server/tools/intro.js +53 -0
  66. package/dist/mcp-server/tools/intro.js.map +1 -0
  67. package/dist/mcp-server/tools/protocol.d.ts +3 -0
  68. package/dist/mcp-server/tools/protocol.d.ts.map +1 -0
  69. package/dist/mcp-server/tools/protocol.js +73 -0
  70. package/dist/mcp-server/tools/protocol.js.map +1 -0
  71. package/dist/mcp-server/tools/talent.d.ts +3 -0
  72. package/dist/mcp-server/tools/talent.d.ts.map +1 -0
  73. package/dist/mcp-server/tools/talent.js +226 -0
  74. package/dist/mcp-server/tools/talent.js.map +1 -0
  75. package/dist/openclaw/index.d.ts +2 -0
  76. package/dist/openclaw/index.d.ts.map +1 -0
  77. package/dist/openclaw/index.js +2 -0
  78. package/dist/openclaw/index.js.map +1 -0
  79. package/dist/openclaw/skill.d.ts +13 -0
  80. package/dist/openclaw/skill.d.ts.map +1 -0
  81. package/dist/openclaw/skill.js +18 -0
  82. package/dist/openclaw/skill.js.map +1 -0
  83. package/dist/protocol/consent.schema.d.ts +18 -48
  84. package/dist/protocol/consent.schema.d.ts.map +1 -1
  85. package/dist/protocol/consent.schema.js +1 -1
  86. package/dist/protocol/consent.schema.js.map +1 -1
  87. package/dist/protocol/dialogue.schema.d.ts +21 -177
  88. package/dist/protocol/dialogue.schema.d.ts.map +1 -1
  89. package/dist/protocol/envelope.schema.d.ts +46 -28
  90. package/dist/protocol/envelope.schema.d.ts.map +1 -1
  91. package/dist/protocol/errors.d.ts +8 -1
  92. package/dist/protocol/errors.d.ts.map +1 -1
  93. package/dist/protocol/handshake.schema.d.ts +130 -385
  94. package/dist/protocol/handshake.schema.d.ts.map +1 -1
  95. package/dist/protocol/handshake.schema.js +1 -0
  96. package/dist/protocol/handshake.schema.js.map +1 -1
  97. package/dist/protocol/identity.schema.d.ts +44 -94
  98. package/dist/protocol/identity.schema.d.ts.map +1 -1
  99. package/dist/protocol/index.d.ts +1 -0
  100. package/dist/protocol/index.d.ts.map +1 -1
  101. package/dist/protocol/index.js +1 -0
  102. package/dist/protocol/index.js.map +1 -1
  103. package/dist/protocol/message-types.d.ts +14 -1
  104. package/dist/protocol/message-types.d.ts.map +1 -1
  105. package/dist/protocol/message.schema.d.ts +100 -715
  106. package/dist/protocol/message.schema.d.ts.map +1 -1
  107. package/dist/protocol/resolution.schema.d.ts +22 -268
  108. package/dist/protocol/resolution.schema.d.ts.map +1 -1
  109. package/dist/protocol/resolution.schema.js +1 -1
  110. package/dist/protocol/resolution.schema.js.map +1 -1
  111. package/dist/protocol/state-machine.d.ts +10 -1
  112. package/dist/protocol/state-machine.d.ts.map +1 -1
  113. package/dist/protocol/talent.schema.d.ts +106 -0
  114. package/dist/protocol/talent.schema.d.ts.map +1 -0
  115. package/dist/protocol/talent.schema.js +47 -0
  116. package/dist/protocol/talent.schema.js.map +1 -0
  117. package/dist/protocol/transport.schema.d.ts +16 -18
  118. package/dist/protocol/transport.schema.d.ts.map +1 -1
  119. package/dist/transport/client.d.ts +32 -0
  120. package/dist/transport/client.d.ts.map +1 -0
  121. package/dist/transport/client.js +155 -0
  122. package/dist/transport/client.js.map +1 -0
  123. package/dist/transport/dedup.d.ts +9 -0
  124. package/dist/transport/dedup.d.ts.map +1 -0
  125. package/dist/transport/dedup.js +36 -0
  126. package/dist/transport/dedup.js.map +1 -0
  127. package/dist/transport/handler.d.ts +9 -0
  128. package/dist/transport/handler.d.ts.map +1 -0
  129. package/dist/transport/handler.js +105 -0
  130. package/dist/transport/handler.js.map +1 -0
  131. package/dist/transport/hmac.d.ts +3 -0
  132. package/dist/transport/hmac.d.ts.map +1 -0
  133. package/dist/transport/hmac.js +43 -0
  134. package/dist/transport/hmac.js.map +1 -0
  135. package/dist/transport/index.d.ts +6 -0
  136. package/dist/transport/index.d.ts.map +1 -0
  137. package/dist/transport/index.js +6 -0
  138. package/dist/transport/index.js.map +1 -0
  139. package/dist/transport/reference-runner.d.ts +37 -0
  140. package/dist/transport/reference-runner.d.ts.map +1 -0
  141. package/dist/transport/reference-runner.js +372 -0
  142. package/dist/transport/reference-runner.js.map +1 -0
  143. package/package.json +19 -31
  144. package/dist/agent/archiver.d.ts +0 -8
  145. package/dist/agent/archiver.d.ts.map +0 -1
  146. package/dist/agent/archiver.js +0 -48
  147. package/dist/agent/archiver.js.map +0 -1
  148. package/dist/agent/capabilities.d.ts +0 -23
  149. package/dist/agent/capabilities.d.ts.map +0 -1
  150. package/dist/agent/capabilities.js +0 -87
  151. package/dist/agent/capabilities.js.map +0 -1
  152. package/dist/agent/config.d.ts +0 -60
  153. package/dist/agent/config.d.ts.map +0 -1
  154. package/dist/agent/config.js +0 -84
  155. package/dist/agent/config.js.map +0 -1
  156. package/dist/agent/context-provider.d.ts +0 -12
  157. package/dist/agent/context-provider.d.ts.map +0 -1
  158. package/dist/agent/context-provider.js +0 -34
  159. package/dist/agent/context-provider.js.map +0 -1
  160. package/dist/agent/context.d.ts +0 -9
  161. package/dist/agent/context.d.ts.map +0 -1
  162. package/dist/agent/context.js +0 -80
  163. package/dist/agent/context.js.map +0 -1
  164. package/dist/agent/events.d.ts +0 -62
  165. package/dist/agent/events.d.ts.map +0 -1
  166. package/dist/agent/events.js +0 -21
  167. package/dist/agent/events.js.map +0 -1
  168. package/dist/agent/index.d.ts +0 -32
  169. package/dist/agent/index.d.ts.map +0 -1
  170. package/dist/agent/index.js +0 -28
  171. package/dist/agent/index.js.map +0 -1
  172. package/dist/agent/mcp.d.ts +0 -16
  173. package/dist/agent/mcp.d.ts.map +0 -1
  174. package/dist/agent/mcp.js +0 -69
  175. package/dist/agent/mcp.js.map +0 -1
  176. package/dist/agent/notifications/decision-parser.d.ts +0 -10
  177. package/dist/agent/notifications/decision-parser.d.ts.map +0 -1
  178. package/dist/agent/notifications/decision-parser.js +0 -21
  179. package/dist/agent/notifications/decision-parser.js.map +0 -1
  180. package/dist/agent/notifications/index.d.ts +0 -4
  181. package/dist/agent/notifications/index.d.ts.map +0 -1
  182. package/dist/agent/notifications/index.js +0 -3
  183. package/dist/agent/notifications/index.js.map +0 -1
  184. package/dist/agent/notifications/opportunity-templates.d.ts +0 -14
  185. package/dist/agent/notifications/opportunity-templates.d.ts.map +0 -1
  186. package/dist/agent/notifications/opportunity-templates.js +0 -21
  187. package/dist/agent/notifications/opportunity-templates.js.map +0 -1
  188. package/dist/agent/notifications/types.d.ts +0 -16
  189. package/dist/agent/notifications/types.d.ts.map +0 -1
  190. package/dist/agent/notifications/types.js +0 -2
  191. package/dist/agent/notifications/types.js.map +0 -1
  192. package/dist/agent/providers.d.ts +0 -9
  193. package/dist/agent/providers.d.ts.map +0 -1
  194. package/dist/agent/providers.js +0 -29
  195. package/dist/agent/providers.js.map +0 -1
  196. package/dist/agent/runtime.d.ts +0 -63
  197. package/dist/agent/runtime.d.ts.map +0 -1
  198. package/dist/agent/runtime.js +0 -395
  199. package/dist/agent/runtime.js.map +0 -1
  200. package/dist/agent/scanning/index.d.ts +0 -3
  201. package/dist/agent/scanning/index.d.ts.map +0 -1
  202. package/dist/agent/scanning/index.js +0 -3
  203. package/dist/agent/scanning/index.js.map +0 -1
  204. package/dist/agent/scanning/opportunity-scorer.d.ts +0 -24
  205. package/dist/agent/scanning/opportunity-scorer.d.ts.map +0 -1
  206. package/dist/agent/scanning/opportunity-scorer.js +0 -90
  207. package/dist/agent/scanning/opportunity-scorer.js.map +0 -1
  208. package/dist/agent/scanning/types.d.ts +0 -65
  209. package/dist/agent/scanning/types.d.ts.map +0 -1
  210. package/dist/agent/scanning/types.js +0 -32
  211. package/dist/agent/scanning/types.js.map +0 -1
  212. package/dist/agent/scheduler.d.ts +0 -38
  213. package/dist/agent/scheduler.d.ts.map +0 -1
  214. package/dist/agent/scheduler.js +0 -125
  215. package/dist/agent/scheduler.js.map +0 -1
  216. package/dist/agent/session.d.ts +0 -20
  217. package/dist/agent/session.d.ts.map +0 -1
  218. package/dist/agent/session.js +0 -88
  219. package/dist/agent/session.js.map +0 -1
  220. package/dist/agent/stores.d.ts +0 -48
  221. package/dist/agent/stores.d.ts.map +0 -1
  222. package/dist/agent/stores.js +0 -2
  223. package/dist/agent/stores.js.map +0 -1
  224. package/dist/agent/tools/browser/ats-patterns.d.ts +0 -20
  225. package/dist/agent/tools/browser/ats-patterns.d.ts.map +0 -1
  226. package/dist/agent/tools/browser/ats-patterns.js +0 -226
  227. package/dist/agent/tools/browser/ats-patterns.js.map +0 -1
  228. package/dist/agent/tools/browser/index.d.ts +0 -14
  229. package/dist/agent/tools/browser/index.d.ts.map +0 -1
  230. package/dist/agent/tools/browser/index.js +0 -126
  231. package/dist/agent/tools/browser/index.js.map +0 -1
  232. package/dist/agent/tools/browser/operator-runtime.d.ts +0 -35
  233. package/dist/agent/tools/browser/operator-runtime.d.ts.map +0 -1
  234. package/dist/agent/tools/browser/operator-runtime.js +0 -93
  235. package/dist/agent/tools/browser/operator-runtime.js.map +0 -1
  236. package/dist/agent/tools/browser/providers/chrome-mcp.d.ts +0 -3
  237. package/dist/agent/tools/browser/providers/chrome-mcp.d.ts.map +0 -1
  238. package/dist/agent/tools/browser/providers/chrome-mcp.js +0 -164
  239. package/dist/agent/tools/browser/providers/chrome-mcp.js.map +0 -1
  240. package/dist/agent/tools/browser/providers/playwright.d.ts +0 -7
  241. package/dist/agent/tools/browser/providers/playwright.d.ts.map +0 -1
  242. package/dist/agent/tools/browser/providers/playwright.js +0 -619
  243. package/dist/agent/tools/browser/providers/playwright.js.map +0 -1
  244. package/dist/agent/tools/browser/types.d.ts +0 -22
  245. package/dist/agent/tools/browser/types.d.ts.map +0 -1
  246. package/dist/agent/tools/browser/types.js +0 -15
  247. package/dist/agent/tools/browser/types.js.map +0 -1
  248. package/dist/agent/tools/cancel-task.d.ts +0 -4
  249. package/dist/agent/tools/cancel-task.d.ts.map +0 -1
  250. package/dist/agent/tools/cancel-task.js +0 -29
  251. package/dist/agent/tools/cancel-task.js.map +0 -1
  252. package/dist/agent/tools/career-advice.d.ts +0 -3
  253. package/dist/agent/tools/career-advice.d.ts.map +0 -1
  254. package/dist/agent/tools/career-advice.js +0 -49
  255. package/dist/agent/tools/career-advice.js.map +0 -1
  256. package/dist/agent/tools/index.d.ts +0 -15
  257. package/dist/agent/tools/index.d.ts.map +0 -1
  258. package/dist/agent/tools/index.js +0 -94
  259. package/dist/agent/tools/index.js.map +0 -1
  260. package/dist/agent/tools/job-search.d.ts +0 -3
  261. package/dist/agent/tools/job-search.d.ts.map +0 -1
  262. package/dist/agent/tools/job-search.js +0 -77
  263. package/dist/agent/tools/job-search.js.map +0 -1
  264. package/dist/agent/tools/list-tasks.d.ts +0 -4
  265. package/dist/agent/tools/list-tasks.d.ts.map +0 -1
  266. package/dist/agent/tools/list-tasks.js +0 -24
  267. package/dist/agent/tools/list-tasks.js.map +0 -1
  268. package/dist/agent/tools/market-data.d.ts +0 -8
  269. package/dist/agent/tools/market-data.d.ts.map +0 -1
  270. package/dist/agent/tools/market-data.js +0 -133
  271. package/dist/agent/tools/market-data.js.map +0 -1
  272. package/dist/agent/tools/memory-write.d.ts +0 -3
  273. package/dist/agent/tools/memory-write.d.ts.map +0 -1
  274. package/dist/agent/tools/memory-write.js +0 -48
  275. package/dist/agent/tools/memory-write.js.map +0 -1
  276. package/dist/agent/tools/resume.d.ts +0 -3
  277. package/dist/agent/tools/resume.d.ts.map +0 -1
  278. package/dist/agent/tools/resume.js +0 -70
  279. package/dist/agent/tools/resume.js.map +0 -1
  280. package/dist/agent/tools/schedule-task.d.ts +0 -4
  281. package/dist/agent/tools/schedule-task.d.ts.map +0 -1
  282. package/dist/agent/tools/schedule-task.js +0 -39
  283. package/dist/agent/tools/schedule-task.js.map +0 -1
  284. package/dist/agent/tools/shell.d.ts +0 -6
  285. package/dist/agent/tools/shell.d.ts.map +0 -1
  286. package/dist/agent/tools/shell.js +0 -66
  287. package/dist/agent/tools/shell.js.map +0 -1
  288. package/dist/agent/tools/web-search.d.ts +0 -6
  289. package/dist/agent/tools/web-search.d.ts.map +0 -1
  290. package/dist/agent/tools/web-search.js +0 -73
  291. package/dist/agent/tools/web-search.js.map +0 -1
  292. package/dist/agent/types.d.ts +0 -103
  293. package/dist/agent/types.d.ts.map +0 -1
  294. package/dist/agent/types.js +0 -11
  295. package/dist/agent/types.js.map +0 -1
  296. package/dist/channels/index.d.ts +0 -10
  297. package/dist/channels/index.d.ts.map +0 -1
  298. package/dist/channels/index.js +0 -15
  299. package/dist/channels/index.js.map +0 -1
  300. package/dist/channels/telegram.d.ts +0 -21
  301. package/dist/channels/telegram.d.ts.map +0 -1
  302. package/dist/channels/telegram.js +0 -255
  303. package/dist/channels/telegram.js.map +0 -1
  304. package/dist/channels/types.d.ts +0 -24
  305. package/dist/channels/types.d.ts.map +0 -1
  306. package/dist/channels/types.js +0 -2
  307. package/dist/channels/types.js.map +0 -1
  308. package/dist/cli/templates/HEARTBEAT.md +0 -6
  309. package/dist/cli/templates/MEMORY.md +0 -6
  310. package/dist/cli/templates/PREFERENCES.md +0 -40
  311. package/dist/cli/templates/PROFILE.md +0 -26
  312. package/dist/cli/templates/SOUL.md +0 -23
  313. package/dist/connectors/google-calendar.d.ts +0 -8
  314. package/dist/connectors/google-calendar.d.ts.map +0 -1
  315. package/dist/connectors/google-calendar.js +0 -23
  316. package/dist/connectors/google-calendar.js.map +0 -1
  317. package/dist/connectors/google-gmail.d.ts +0 -8
  318. package/dist/connectors/google-gmail.d.ts.map +0 -1
  319. package/dist/connectors/google-gmail.js +0 -30
  320. package/dist/connectors/google-gmail.js.map +0 -1
  321. package/dist/connectors/google-oauth.d.ts +0 -17
  322. package/dist/connectors/google-oauth.d.ts.map +0 -1
  323. package/dist/connectors/google-oauth.js +0 -52
  324. package/dist/connectors/google-oauth.js.map +0 -1
  325. package/dist/connectors/index.d.ts +0 -5
  326. package/dist/connectors/index.d.ts.map +0 -1
  327. package/dist/connectors/index.js +0 -5
  328. package/dist/connectors/index.js.map +0 -1
  329. package/dist/connectors/types.d.ts +0 -20
  330. package/dist/connectors/types.d.ts.map +0 -1
  331. package/dist/connectors/types.js +0 -5
  332. package/dist/connectors/types.js.map +0 -1
package/dist/cli/index.js CHANGED
@@ -1,434 +1,501 @@
1
1
  #!/usr/bin/env node
2
- import * as readline from "node:readline/promises";
3
- import * as fs from "node:fs/promises";
4
- import * as fsSync from "node:fs";
5
- import * as path from "node:path";
6
- import { stdin, stdout } from "node:process";
7
- import { fileURLToPath } from "node:url";
8
- const ARTEMYS_DIR = path.join(process.env.HOME ?? "~", ".artemys");
9
- const CONFIG_PATH = path.join(ARTEMYS_DIR, "config.json");
10
- function templatesDir() {
11
- return path.join(path.dirname(fileURLToPath(import.meta.url)), "templates");
12
- }
13
- async function onboard() {
14
- const existing = await readRawConfig();
15
- const rl = readline.createInterface({ input: stdin, output: stdout });
16
- console.log("\nArtemys onboarding configure your Artie runtime.\n");
17
- const apiKey = await askWithDefault(rl, "Anthropic API key (or press Enter to skip)", asString(existing.anthropic_api_key) ?? "");
18
- const openaiKey = await askWithDefault(rl, "OpenAI API key (optional, press Enter to skip)", asString(existing.openai_api_key) ?? "");
19
- const botToken = await askRequired(rl, "Telegram bot token", asString(existing.telegram_bot_token));
20
- const model = await askWithDefault(rl, "Default model (provider:model)", asString(existing.model) ?? "anthropic:claude-haiku-4-5-20251001");
21
- const storagePath = await askWithDefault(rl, "Session storage path", asString(existing.storage_path) ?? "~/.artemys/sessions");
22
- rl.close();
23
- await fs.mkdir(ARTEMYS_DIR, { recursive: true });
24
- const config = {
25
- ...existing,
26
- telegram_bot_token: botToken,
27
- model,
28
- storage_path: storagePath,
29
- };
30
- if (apiKey)
31
- config.anthropic_api_key = apiKey;
32
- if (openaiKey)
33
- config.openai_api_key = openaiKey;
34
- await fs.writeFile(CONFIG_PATH, JSON.stringify(config, null, 2));
35
- await copyTemplate(templatesDir(), "PROFILE.md");
36
- await copyTemplate(templatesDir(), "PREFERENCES.md");
37
- await copyTemplate(templatesDir(), "SOUL.md");
38
- await copyTemplate(templatesDir(), "MEMORY.md");
39
- await copyTemplate(templatesDir(), "HEARTBEAT.md");
40
- await fs.mkdir(expandPath(storagePath), { recursive: true });
41
- console.log(`\nConfiguration saved to ${CONFIG_PATH}`);
42
- console.log("Templates saved to ~/.artemys/");
43
- console.log("\nNext steps:");
44
- console.log(" 1. Edit ~/.artemys/PROFILE.md with your professional info");
45
- console.log(" 2. Edit ~/.artemys/PREFERENCES.md with your job preferences");
46
- console.log(" 3. Edit ~/.artemys/SOUL.md to customize Artie's personality");
47
- console.log(" 4. Run: artemys doctor");
48
- console.log(" 5. Run: artemys start\n");
2
+ import { readFile } from "node:fs/promises";
3
+ import process from "node:process";
4
+ import { pathToFileURL } from "node:url";
5
+ import { CoffeeShopClient } from "../coffeeshop/index.js";
6
+ import { AgentCardSchema, DiscoveryQuerySchema, } from "../discovery/index.js";
7
+ import { ConversationTracker, ProfileStore, SqliteMcpPersistence, createPersistentConversationTracker, createPersistentProfileStore, startArtemysMcpServer, } from "../mcp-server/index.js";
8
+ import { registerTalentTools } from "../mcp-server/tools/talent.js";
9
+ import { ProtocolTransportClient } from "../transport/index.js";
10
+ const DEFAULT_COFFEESHOP_URL = "https://coffeeshop.artemys.ai";
11
+ const DEFAULT_MAX_TRACKED_CONVERSATIONS = 1_000;
12
+ const DEFAULT_CONVERSATION_TTL_MS = 24 * 60 * 60 * 1000;
13
+ function parseArgs(argv) {
14
+ const positionals = [];
15
+ const flags = {};
16
+ for (let index = 0; index < argv.length; index += 1) {
17
+ const token = argv[index];
18
+ if (!token.startsWith("--")) {
19
+ positionals.push(token);
20
+ continue;
21
+ }
22
+ const key = token.slice(2);
23
+ const next = argv[index + 1];
24
+ if (!next || next.startsWith("--")) {
25
+ flags[key] = true;
26
+ continue;
27
+ }
28
+ if (key === "capability") {
29
+ const current = flags[key];
30
+ if (Array.isArray(current)) {
31
+ current.push(next);
32
+ }
33
+ else if (typeof current === "string") {
34
+ flags[key] = [current, next];
35
+ }
36
+ else {
37
+ flags[key] = [next];
38
+ }
39
+ }
40
+ else {
41
+ flags[key] = next;
42
+ }
43
+ index += 1;
44
+ }
45
+ return { positionals, flags };
49
46
  }
50
- async function init() {
51
- await onboard();
47
+ function getFlagString(flags, key) {
48
+ const value = flags[key];
49
+ return typeof value === "string" ? value : undefined;
52
50
  }
53
- async function start() {
54
- const { loadConfig } = await import("../agent/config.js");
55
- const { ArtemysRuntime } = await import("../agent/runtime.js");
56
- const { TelegramAdapter } = await import("../channels/telegram.js");
57
- let config;
58
- try {
59
- config = await loadConfig();
51
+ function getFlagBoolean(flags, key) {
52
+ const value = flags[key];
53
+ if (typeof value === "boolean") {
54
+ return value;
60
55
  }
61
- catch (err) {
62
- if (err instanceof Error && err.name === "ZodError") {
63
- console.error(`\nConfiguration error: missing or invalid fields in ~/.artemys/config.json`);
64
- console.error("Run 'artemys onboard' to set up your configuration.\n");
65
- process.exit(1);
56
+ if (typeof value === "string") {
57
+ const normalized = value.trim().toLowerCase();
58
+ if (normalized === "true") {
59
+ return true;
60
+ }
61
+ if (normalized === "false") {
62
+ return false;
66
63
  }
67
- throw err;
68
64
  }
69
- const runtime = new ArtemysRuntime(config);
70
- const telegram = new TelegramAdapter(config.telegram_bot_token);
71
- try {
72
- await runtime.start([telegram]);
73
- }
74
- catch (err) {
75
- const msg = err instanceof Error ? err.message : String(err);
76
- if (msg.includes("404") || msg.includes("401") || msg.includes("Not Found")) {
77
- console.error(`\nFailed to connect to Telegram: invalid bot token.`);
78
- console.error("Check your token in ~/.artemys/config.json and try again.\n");
79
- process.exit(1);
65
+ return undefined;
66
+ }
67
+ function getPersistOption(flags) {
68
+ const value = flags.persist;
69
+ if (typeof value === "boolean") {
70
+ return value;
71
+ }
72
+ if (typeof value === "string") {
73
+ const trimmed = value.trim();
74
+ if (trimmed.length === 0) {
75
+ return true;
80
76
  }
81
- throw err;
77
+ const normalized = trimmed.toLowerCase();
78
+ if (normalized === "true") {
79
+ return true;
80
+ }
81
+ if (normalized === "false") {
82
+ return false;
83
+ }
84
+ return trimmed;
82
85
  }
83
- console.log("\nArtie is online — listening on Telegram");
84
- console.log("Press Ctrl+C to stop\n");
85
- const shutdown = async () => {
86
- console.log("\nShutting down...");
87
- await runtime.stop();
88
- process.exit(0);
89
- };
90
- process.on("SIGINT", shutdown);
91
- process.on("SIGTERM", shutdown);
86
+ return undefined;
87
+ }
88
+ function getCsvFlagList(flags, key) {
89
+ const value = getFlagString(flags, key);
90
+ if (!value) {
91
+ return undefined;
92
+ }
93
+ const items = value
94
+ .split(",")
95
+ .map((entry) => entry.trim())
96
+ .filter((entry) => entry.length > 0);
97
+ return items.length > 0 ? items : undefined;
92
98
  }
93
99
  function printHelp() {
94
100
  console.log(`
95
- artemys Run your own Artie agent
101
+ artemys - Protocol + Coffee Shop + MCP Server SDK CLI
96
102
 
97
103
  Commands:
98
- onboard Guided setup for keys, model, and templates
99
- init Alias for onboard
100
- doctor Validate local config and safety checks
101
- start Start the agent (connects to Telegram)
104
+ mcp-server Start Artemys MCP server
105
+ talent Candidate talent workflow commands
106
+ register Register an agent card with Coffee Shop
107
+ discover Discover agents via Coffee Shop
108
+ rotate-key Rotate Coffee Shop API key
109
+ intro-events Show intro lifecycle events
110
+ version Show CLI version
111
+ help Show this help message
112
+
113
+ Examples:
114
+ artemys mcp-server --agent-card ./agent-card.json
115
+ artemys mcp-server --agent-card ./agent-card.json --persist
116
+ artemys register --agent-card ./agent-card.json
117
+ artemys discover --requester-agent-id agent-123 --role talent_agent
118
+ artemys talent search --agent-card ./agent-card.json --role-keywords backend,platform --remote-ok
119
+ artemys talent apply --agent-card ./agent-card.json --target-agent-id talent-1 --target-endpoint https://talent.example.com/messages --job-posting-ref job-123 --persist
120
+ artemys talent profile --agent-card ./agent-card.json --profile-file ./candidate-profile.json --persist
121
+ artemys rotate-key --agent-id agent-123 --api-key old-key
122
+ artemys intro-events --intro-id intro-abc --api-key key
123
+ `);
124
+ }
125
+ function printTalentHelp() {
126
+ console.log(`
127
+ artemys talent - Candidate talent workflow commands
128
+
129
+ Subcommands:
130
+ search Discover opportunities from talent agents
131
+ apply Express interest in a specific job posting
132
+ status Check tracked conversation status
133
+ profile Update stored candidate profile
102
134
  help Show this help message
103
135
 
104
- Setup:
105
- 1. artemys onboard
106
- 2. Edit ~/.artemys/PROFILE.md
107
- 3. Edit ~/.artemys/PREFERENCES.md
108
- 4. artemys doctor
109
- 5. artemys start
136
+ Examples:
137
+ artemys talent search --agent-card ./agent-card.json --role-keywords backend,platform --remote-ok --limit 20
138
+ artemys talent apply --agent-card ./agent-card.json --target-agent-id talent-1 --target-endpoint https://talent.example.com/messages --job-posting-ref job-123 --match-reasoning "Strong backend fit"
139
+ artemys talent status --agent-card ./agent-card.json --status-filter dialogue_active --persist
140
+ artemys talent profile --agent-card ./agent-card.json --profile-file ./candidate-profile.json --sync-agent-card --persist ~/.artemys/state.db
141
+
142
+ Common flags:
143
+ --agent-card <path> Required for all talent subcommands except help
144
+ --coffeeshop-url <url> Override Coffee Shop base URL
145
+ --persist [path] Persist profile + conversations to SQLite (default: ~/.artemys/state.db)
110
146
  `);
111
147
  }
112
- function parseDoctorOptions(argv) {
148
+ async function readAgentCardFromPath(pathValue) {
149
+ const raw = await readFile(pathValue, "utf-8");
150
+ const parsed = JSON.parse(raw);
151
+ return AgentCardSchema.parse(parsed);
152
+ }
153
+ function buildNetworkDeps(args, agentCard) {
154
+ const coffeeShopUrl = getFlagString(args.flags, "coffeeshop-url") ?? DEFAULT_COFFEESHOP_URL;
155
+ const hasCoffeeShopApiKey = typeof process.env.ARTEMYS_COFFEESHOP_API_KEY === "string" &&
156
+ process.env.ARTEMYS_COFFEESHOP_API_KEY.length > 0;
157
+ const coffeeShopClient = new CoffeeShopClient({
158
+ baseUrl: coffeeShopUrl,
159
+ apiKey: process.env.ARTEMYS_COFFEESHOP_API_KEY,
160
+ agentId: agentCard.agent_id,
161
+ });
162
+ const transportClient = new ProtocolTransportClient({
163
+ agentId: agentCard.agent_id,
164
+ getSharedSecret: loadSharedSecretResolver({
165
+ coffeeShopClient: hasCoffeeShopApiKey ? coffeeShopClient : undefined,
166
+ }),
167
+ });
113
168
  return {
114
- fix: argv.includes("--fix"),
115
- json: argv.includes("--json"),
169
+ coffeeShopClient,
170
+ transportClient,
171
+ hasCoffeeShopApiKey,
116
172
  };
117
173
  }
118
- async function doctor(options) {
119
- const checks = await runDoctorChecks(options);
120
- const failing = checks.filter((check) => check.status === "fail");
121
- const criticalFailures = failing.filter((check) => check.severity === "critical");
122
- if (options.json) {
123
- console.log(JSON.stringify({
124
- healthy: failing.length === 0,
125
- failures: failing.length,
126
- critical_failures: criticalFailures.length,
127
- checks,
128
- }, null, 2));
129
- }
130
- else {
131
- console.log("\nArtemys doctor\n");
132
- for (const check of checks) {
133
- const icon = check.status === "pass" ? "PASS" : "FAIL";
134
- const fix = check.fixable
135
- ? check.fixed
136
- ? " (fixed)"
137
- : " (fixable with --fix)"
138
- : "";
139
- const target = check.path ? ` [${check.path}]` : "";
140
- console.log(`${icon} [${check.severity}] ${check.id}: ${check.message}${fix}${target}`);
141
- }
142
- console.log("");
143
- if (failing.length === 0) {
144
- console.log("Doctor check passed: runtime looks healthy.\n");
145
- }
146
- else {
147
- console.log(`Doctor found ${failing.length} issue(s), including ${criticalFailures.length} critical.`);
148
- console.log("Use `artemys doctor --fix` to apply safe automatic repairs.\n");
149
- }
150
- }
151
- if (failing.length > 0) {
152
- process.exit(1);
174
+ function buildTalentState(flags) {
175
+ const persistOption = getPersistOption(flags);
176
+ if (!persistOption) {
177
+ return {
178
+ tracker: new ConversationTracker({
179
+ maxConversations: DEFAULT_MAX_TRACKED_CONVERSATIONS,
180
+ conversationTtlMs: DEFAULT_CONVERSATION_TTL_MS,
181
+ }),
182
+ profileStore: new ProfileStore(),
183
+ close: () => { },
184
+ };
153
185
  }
154
- }
155
- async function runDoctorChecks(options) {
156
- const checks = [];
157
- const configExists = await pathExists(CONFIG_PATH);
158
- checks.push({
159
- id: "config.exists",
160
- severity: "critical",
161
- status: configExists ? "pass" : "fail",
162
- message: configExists
163
- ? "Config file exists"
164
- : "Config file is missing. Run `artemys onboard` first.",
165
- path: CONFIG_PATH,
166
- fixable: false,
167
- fixed: false,
186
+ const persistence = new SqliteMcpPersistence({
187
+ path: typeof persistOption === "string" ? persistOption : undefined,
168
188
  });
169
- if (!configExists) {
170
- return checks;
189
+ return {
190
+ tracker: createPersistentConversationTracker(persistence, {
191
+ maxConversations: DEFAULT_MAX_TRACKED_CONVERSATIONS,
192
+ conversationTtlMs: DEFAULT_CONVERSATION_TTL_MS,
193
+ }),
194
+ profileStore: createPersistentProfileStore(persistence),
195
+ close: () => {
196
+ persistence.close();
197
+ },
198
+ };
199
+ }
200
+ function buildTalentToolHandlers(deps) {
201
+ const handlers = new Map();
202
+ registerTalentTools({
203
+ registerTool: (name, _config, handler) => {
204
+ handlers.set(name, handler);
205
+ },
206
+ }, deps);
207
+ return handlers;
208
+ }
209
+ function extractToolResponseData(response) {
210
+ const structuredData = response.structuredContent?.data;
211
+ if (structuredData !== undefined) {
212
+ return structuredData;
213
+ }
214
+ const textContent = response.content[0]?.text;
215
+ if (typeof textContent !== "string" || textContent.length === 0) {
216
+ return null;
171
217
  }
172
- let rawConfig;
173
218
  try {
174
- const raw = await fs.readFile(CONFIG_PATH, "utf-8");
175
- rawConfig = JSON.parse(raw);
176
- checks.push({
177
- id: "config.valid_json",
178
- severity: "critical",
179
- status: "pass",
180
- message: "Config JSON is valid",
181
- path: CONFIG_PATH,
182
- fixable: false,
183
- fixed: false,
184
- });
219
+ return JSON.parse(textContent);
185
220
  }
186
221
  catch {
187
- checks.push({
188
- id: "config.valid_json",
189
- severity: "critical",
190
- status: "fail",
191
- message: "Config file is not valid JSON",
192
- path: CONFIG_PATH,
193
- fixable: false,
194
- fixed: false,
195
- });
196
- return checks;
197
- }
198
- // At least one provider auth required
199
- const hasAnthropic = !!asString(rawConfig.anthropic_api_key) || !!asString(rawConfig.anthropic_auth_token);
200
- const hasOpenai = !!asString(rawConfig.openai_api_key) || !!asString(rawConfig.openai_auth_token);
201
- checks.push({
202
- id: "config.required.provider_auth",
203
- severity: "critical",
204
- status: hasAnthropic || hasOpenai ? "pass" : "fail",
205
- message: hasAnthropic || hasOpenai
206
- ? `Provider auth configured (anthropic: ${hasAnthropic}, openai: ${hasOpenai})`
207
- : "No provider auth configured. Set at least one of: anthropic_api_key, openai_api_key",
208
- path: CONFIG_PATH,
209
- fixable: false,
210
- fixed: false,
211
- });
212
- const botToken = asString(rawConfig.telegram_bot_token);
213
- checks.push({
214
- id: "config.required.telegram_bot_token",
215
- severity: "critical",
216
- status: botToken ? "pass" : "fail",
217
- message: botToken ? "telegram_bot_token is set" : "telegram_bot_token is missing or empty",
218
- path: CONFIG_PATH,
219
- fixable: false,
220
- fixed: false,
221
- });
222
- // Validate model string has provider prefix
223
- const model = asString(rawConfig.model) ?? "anthropic:claude-haiku-4-5-20251001";
224
- checks.push({
225
- id: "config.model_format",
226
- severity: "warning",
227
- status: model.includes(":") ? "pass" : "fail",
228
- message: model.includes(":")
229
- ? `Model is provider-prefixed: ${model}`
230
- : `Model "${model}" should be provider-prefixed (e.g. "anthropic:claude-haiku-4-5-20251001")`,
231
- fixable: false,
232
- fixed: false,
233
- });
234
- const profilePath = expandPath(asString(rawConfig.profile_path) ?? "~/.artemys/PROFILE.md");
235
- const preferencesPath = expandPath(asString(rawConfig.preferences_path) ?? "~/.artemys/PREFERENCES.md");
236
- const soulPath = path.join(ARTEMYS_DIR, "SOUL.md");
237
- const storagePath = expandPath(asString(rawConfig.storage_path) ?? "~/.artemys/sessions");
238
- checks.push(await ensureFileCheck({
239
- id: "files.profile",
240
- targetPath: profilePath,
241
- templateName: "PROFILE.md",
242
- options,
243
- message: "Profile file exists",
244
- }));
245
- checks.push(await ensureFileCheck({
246
- id: "files.preferences",
247
- targetPath: preferencesPath,
248
- templateName: "PREFERENCES.md",
249
- options,
250
- message: "Preferences file exists",
251
- }));
252
- checks.push(await ensureFileCheck({
253
- id: "files.soul",
254
- targetPath: soulPath,
255
- templateName: "SOUL.md",
256
- options,
257
- message: "Soul file exists",
258
- }));
259
- const storageExists = await pathExists(storagePath);
260
- let storageFixed = false;
261
- if (!storageExists && options.fix) {
262
- await fs.mkdir(storagePath, { recursive: true });
263
- storageFixed = true;
264
- }
265
- checks.push({
266
- id: "storage.exists",
267
- severity: "warning",
268
- status: storageExists || storageFixed ? "pass" : "fail",
269
- message: storageExists || storageFixed
270
- ? "Session storage directory exists"
271
- : "Session storage directory is missing",
272
- path: storagePath,
273
- fixable: true,
274
- fixed: storageFixed,
275
- });
276
- const writable = await isWritable(storagePath);
277
- checks.push({
278
- id: "storage.writable",
279
- severity: "critical",
280
- status: writable ? "pass" : "fail",
281
- message: writable
282
- ? "Session storage directory is writable"
283
- : "Session storage directory is not writable",
284
- path: storagePath,
285
- fixable: false,
286
- fixed: false,
287
- });
288
- if (process.platform !== "win32") {
289
- const mode = await fileMode(CONFIG_PATH);
290
- const permissive = mode !== null ? (mode & 0o077) > 0 : false;
291
- let fixed = false;
292
- if (permissive && options.fix) {
293
- await fs.chmod(CONFIG_PATH, 0o600);
294
- fixed = true;
295
- }
296
- checks.push({
297
- id: "config.permissions",
298
- severity: "warning",
299
- status: permissive && !fixed ? "fail" : "pass",
300
- message: permissive && !fixed
301
- ? "Config permissions are too open; recommend chmod 600"
302
- : "Config permissions are restricted",
303
- path: CONFIG_PATH,
304
- fixable: true,
305
- fixed,
306
- });
222
+ return textContent;
307
223
  }
308
- return checks;
309
224
  }
310
- async function ensureFileCheck(params) {
311
- const exists = await pathExists(params.targetPath);
312
- let fixed = false;
313
- if (!exists && params.options.fix) {
314
- await fs.mkdir(path.dirname(params.targetPath), { recursive: true });
315
- const templateContent = await fs.readFile(path.join(templatesDir(), params.templateName), "utf-8");
316
- await fs.writeFile(params.targetPath, templateContent);
317
- fixed = true;
225
+ async function invokeTalentTool(handlers, toolName, args) {
226
+ const handler = handlers.get(toolName);
227
+ if (!handler) {
228
+ throw new Error(`Talent tool '${toolName}' is unavailable`);
318
229
  }
319
- return {
320
- id: params.id,
321
- severity: "warning",
322
- status: exists || fixed ? "pass" : "fail",
323
- message: exists || fixed ? params.message : `${params.message.replace("exists", "is missing")}`,
324
- path: params.targetPath,
325
- fixable: true,
326
- fixed,
327
- };
230
+ const response = await handler(args);
231
+ return extractToolResponseData(response);
328
232
  }
329
- async function pathExists(filePath) {
330
- try {
331
- await fs.access(filePath);
332
- return true;
233
+ async function registerCommand(args) {
234
+ const cardPath = getFlagString(args.flags, "agent-card");
235
+ if (!cardPath) {
236
+ throw new Error("Missing required --agent-card <path>");
333
237
  }
334
- catch {
335
- return false;
238
+ const card = await readAgentCardFromPath(cardPath);
239
+ const coffeeShopUrl = getFlagString(args.flags, "coffeeshop-url") ?? DEFAULT_COFFEESHOP_URL;
240
+ const client = new CoffeeShopClient({ baseUrl: coffeeShopUrl });
241
+ const result = await client.register(card);
242
+ console.log(JSON.stringify(result, null, 2));
243
+ console.log("Save api_key now. It is only returned at registration time.");
244
+ }
245
+ async function discoverCommand(args) {
246
+ const requesterAgentId = getFlagString(args.flags, "requester-agent-id");
247
+ if (!requesterAgentId) {
248
+ throw new Error("Missing required --requester-agent-id <agent-id>");
336
249
  }
250
+ const role = getFlagString(args.flags, "role");
251
+ const protocolVersion = getFlagString(args.flags, "protocol-version");
252
+ const limitRaw = getFlagString(args.flags, "limit");
253
+ const capabilitiesRaw = args.flags.capability;
254
+ const capabilities = Array.isArray(capabilitiesRaw)
255
+ ? capabilitiesRaw
256
+ : typeof capabilitiesRaw === "string"
257
+ ? [capabilitiesRaw]
258
+ : undefined;
259
+ const query = DiscoveryQuerySchema.parse({
260
+ requester_agent_id: requesterAgentId,
261
+ ...(role ? { role } : {}),
262
+ ...(protocolVersion ? { protocol_version: protocolVersion } : {}),
263
+ ...(capabilities ? { capabilities_any: capabilities } : {}),
264
+ ...(limitRaw ? { limit: Number.parseInt(limitRaw, 10) } : {}),
265
+ });
266
+ const coffeeShopUrl = getFlagString(args.flags, "coffeeshop-url") ?? DEFAULT_COFFEESHOP_URL;
267
+ const client = new CoffeeShopClient({ baseUrl: coffeeShopUrl });
268
+ const results = await client.discover(query);
269
+ console.log(JSON.stringify(results, null, 2));
337
270
  }
338
- async function isWritable(filePath) {
339
- try {
340
- await fs.access(filePath, fsSync.constants.W_OK);
341
- return true;
271
+ async function rotateKeyCommand(args) {
272
+ const agentId = getFlagString(args.flags, "agent-id");
273
+ if (!agentId) {
274
+ throw new Error("Missing required --agent-id <agent-id>");
342
275
  }
343
- catch {
344
- return false;
276
+ const apiKey = getFlagString(args.flags, "api-key");
277
+ if (!apiKey) {
278
+ throw new Error("Missing required --api-key <api-key>");
345
279
  }
280
+ const coffeeShopUrl = getFlagString(args.flags, "coffeeshop-url") ?? DEFAULT_COFFEESHOP_URL;
281
+ const client = new CoffeeShopClient({
282
+ baseUrl: coffeeShopUrl,
283
+ apiKey,
284
+ agentId,
285
+ });
286
+ const result = await client.rotateApiKey();
287
+ console.log(JSON.stringify(result, null, 2));
288
+ console.log("Save api_key now. It is only returned at rotation time.");
346
289
  }
347
- async function fileMode(filePath) {
348
- try {
349
- const stat = await fs.stat(filePath);
350
- return stat.mode;
290
+ async function introEventsCommand(args) {
291
+ const introId = getFlagString(args.flags, "intro-id");
292
+ if (!introId) {
293
+ throw new Error("Missing required --intro-id <intro-id>");
351
294
  }
352
- catch {
353
- return null;
295
+ const apiKey = getFlagString(args.flags, "api-key");
296
+ if (!apiKey) {
297
+ throw new Error("Missing required --api-key <api-key>");
354
298
  }
299
+ const coffeeShopUrl = getFlagString(args.flags, "coffeeshop-url") ?? DEFAULT_COFFEESHOP_URL;
300
+ const client = new CoffeeShopClient({
301
+ baseUrl: coffeeShopUrl,
302
+ apiKey,
303
+ });
304
+ const events = await client.listIntroEvents(introId);
305
+ console.log(JSON.stringify(events, null, 2));
355
306
  }
356
- async function readRawConfig() {
357
- try {
358
- const raw = await fs.readFile(CONFIG_PATH, "utf-8");
359
- return JSON.parse(raw);
307
+ function loadSharedSecretResolver(options) {
308
+ const fallbackSecret = process.env.ARTEMYS_SHARED_SECRET;
309
+ const fromMap = process.env.ARTEMYS_SHARED_SECRETS;
310
+ const parsedMap = fromMap ? JSON.parse(fromMap) : {};
311
+ return async (targetHint) => {
312
+ const mapped = parsedMap[targetHint];
313
+ if (mapped) {
314
+ return mapped;
315
+ }
316
+ if (fallbackSecret) {
317
+ return fallbackSecret;
318
+ }
319
+ if (options.coffeeShopClient) {
320
+ const resolved = await options.coffeeShopClient.resolveTransportSharedSecret(targetHint);
321
+ return resolved.value;
322
+ }
323
+ throw new Error(`No shared secret found for '${targetHint}'. Set ARTEMYS_SHARED_SECRETS/ARTEMYS_SHARED_SECRET or provide ARTEMYS_COFFEESHOP_API_KEY with accepted intro bootstrap.`);
324
+ };
325
+ }
326
+ async function mcpServerCommand(args) {
327
+ const cardPath = getFlagString(args.flags, "agent-card");
328
+ if (!cardPath) {
329
+ throw new Error("Missing required --agent-card <path>");
360
330
  }
361
- catch {
362
- return {};
331
+ const transport = getFlagString(args.flags, "transport") === "sse" ? "sse" : "stdio";
332
+ const portRaw = getFlagString(args.flags, "port");
333
+ const port = portRaw ? Number.parseInt(portRaw, 10) : 3100;
334
+ const persist = getPersistOption(args.flags);
335
+ const agentCard = await readAgentCardFromPath(cardPath);
336
+ const { coffeeShopClient, transportClient, hasCoffeeShopApiKey } = buildNetworkDeps(args, agentCard);
337
+ const started = await startArtemysMcpServer({
338
+ agentCard,
339
+ coffeeShopClient,
340
+ transportClient,
341
+ transport,
342
+ port,
343
+ ...(persist ? { persist } : {}),
344
+ enableIntroTools: hasCoffeeShopApiKey,
345
+ });
346
+ if (!hasCoffeeShopApiKey) {
347
+ console.error("Artemys MCP intro tools disabled (set ARTEMYS_COFFEESHOP_API_KEY to enable intro APIs)");
363
348
  }
364
- }
365
- function asString(value) {
366
- if (typeof value !== "string") {
367
- return undefined;
349
+ if (transport === "sse") {
350
+ console.error(`Artemys MCP server listening on http://127.0.0.1:${port}/mcp`);
368
351
  }
369
- const trimmed = value.trim();
370
- return trimmed.length > 0 ? trimmed : undefined;
352
+ const shutdown = async () => {
353
+ await started.close();
354
+ process.exit(0);
355
+ };
356
+ process.on("SIGINT", shutdown);
357
+ process.on("SIGTERM", shutdown);
371
358
  }
372
- function expandPath(p) {
373
- if (p === "~") {
374
- return process.env.HOME ?? p;
359
+ async function talentCommand(args) {
360
+ const subcommand = args.positionals[1] ?? "help";
361
+ if (subcommand === "help") {
362
+ printTalentHelp();
363
+ return;
375
364
  }
376
- if (p.startsWith("~/")) {
377
- return path.join(process.env.HOME ?? "~", p.slice(2));
365
+ const cardPath = getFlagString(args.flags, "agent-card");
366
+ if (!cardPath) {
367
+ throw new Error("Missing required --agent-card <path>");
378
368
  }
379
- return p;
380
- }
381
- async function askRequired(rl, label, existingValue) {
382
- while (true) {
383
- const prompt = existingValue
384
- ? `${label} [set, press Enter to keep current]: `
385
- : `${label}: `;
386
- const input = (await rl.question(prompt)).trim();
387
- if (input.length > 0) {
388
- return input;
369
+ const agentCard = await readAgentCardFromPath(cardPath);
370
+ const { coffeeShopClient, transportClient, hasCoffeeShopApiKey } = buildNetworkDeps(args, agentCard);
371
+ const state = buildTalentState(args.flags);
372
+ try {
373
+ const handlers = buildTalentToolHandlers({
374
+ coffeeShopClient,
375
+ transportClient,
376
+ tracker: state.tracker,
377
+ profileStore: state.profileStore,
378
+ agentCard,
379
+ introToolsEnabled: hasCoffeeShopApiKey,
380
+ });
381
+ if (subcommand === "search") {
382
+ const roleKeywords = getCsvFlagList(args.flags, "role-keywords");
383
+ const location = getFlagString(args.flags, "location");
384
+ const remoteOk = getFlagBoolean(args.flags, "remote-ok");
385
+ const seniority = getFlagString(args.flags, "seniority");
386
+ const limitRaw = getFlagString(args.flags, "limit");
387
+ const data = await invokeTalentTool(handlers, "search_opportunities", {
388
+ ...(roleKeywords ? { role_keywords: roleKeywords } : {}),
389
+ ...(location ? { location } : {}),
390
+ ...(typeof remoteOk === "boolean" ? { remote_ok: remoteOk } : {}),
391
+ ...(seniority ? { seniority } : {}),
392
+ ...(limitRaw ? { limit: Number.parseInt(limitRaw, 10) } : {}),
393
+ });
394
+ console.log(JSON.stringify(data, null, 2));
395
+ return;
396
+ }
397
+ if (subcommand === "apply") {
398
+ const targetAgentId = getFlagString(args.flags, "target-agent-id");
399
+ const targetEndpoint = getFlagString(args.flags, "target-endpoint");
400
+ const jobPostingRef = getFlagString(args.flags, "job-posting-ref");
401
+ if (!targetAgentId) {
402
+ throw new Error("Missing required --target-agent-id <agent-id>");
403
+ }
404
+ if (!targetEndpoint) {
405
+ throw new Error("Missing required --target-endpoint <url>");
406
+ }
407
+ if (!jobPostingRef) {
408
+ throw new Error("Missing required --job-posting-ref <job-ref>");
409
+ }
410
+ const matchReasoning = getFlagString(args.flags, "match-reasoning");
411
+ const data = await invokeTalentTool(handlers, "express_interest", {
412
+ target_agent_id: targetAgentId,
413
+ target_endpoint: targetEndpoint,
414
+ job_posting_ref: jobPostingRef,
415
+ ...(matchReasoning ? { match_reasoning: matchReasoning } : {}),
416
+ });
417
+ console.log(JSON.stringify(data, null, 2));
418
+ return;
419
+ }
420
+ if (subcommand === "status") {
421
+ const statusFilter = getFlagString(args.flags, "status-filter");
422
+ const data = await invokeTalentTool(handlers, "check_conversations", {
423
+ ...(statusFilter ? { status_filter: statusFilter } : {}),
424
+ });
425
+ console.log(JSON.stringify(data, null, 2));
426
+ return;
389
427
  }
390
- if (existingValue) {
391
- return existingValue;
428
+ if (subcommand === "profile") {
429
+ const profilePath = getFlagString(args.flags, "profile-file");
430
+ if (!profilePath) {
431
+ throw new Error("Missing required --profile-file <path>");
432
+ }
433
+ const profileRaw = await readFile(profilePath, "utf-8");
434
+ const parsedProfile = JSON.parse(profileRaw);
435
+ if (!parsedProfile || typeof parsedProfile !== "object" || Array.isArray(parsedProfile)) {
436
+ throw new Error("Profile file must contain a JSON object");
437
+ }
438
+ const syncAgentCard = getFlagBoolean(args.flags, "sync-agent-card");
439
+ const data = await invokeTalentTool(handlers, "update_profile", {
440
+ ...parsedProfile,
441
+ ...(typeof syncAgentCard === "boolean" ? { sync_agent_card: syncAgentCard } : {}),
442
+ });
443
+ console.log(JSON.stringify(data, null, 2));
444
+ return;
392
445
  }
393
- console.log(`${label} is required.`);
446
+ throw new Error(`Unknown talent subcommand: ${subcommand}`);
447
+ }
448
+ finally {
449
+ state.close();
394
450
  }
395
451
  }
396
- async function askWithDefault(rl, label, defaultValue) {
397
- const input = (await rl.question(`${label} [${defaultValue}]: `)).trim();
398
- return input.length > 0 ? input : defaultValue;
452
+ async function versionCommand() {
453
+ const packageJsonPath = new URL("../../package.json", import.meta.url);
454
+ const raw = await readFile(packageJsonPath, "utf-8");
455
+ const pkg = JSON.parse(raw);
456
+ console.log(pkg.version);
399
457
  }
400
- async function copyTemplate(templatesDir, filename) {
401
- const src = path.join(templatesDir, filename);
402
- const dest = path.join(ARTEMYS_DIR, filename);
403
- try {
404
- await fs.access(dest);
405
- console.log(` Skipping ${filename} (already exists)`);
458
+ export async function runCli(argv = process.argv.slice(2)) {
459
+ const args = parseArgs(argv);
460
+ const command = args.positionals[0] ?? "help";
461
+ if (command === "help") {
462
+ printHelp();
463
+ return;
406
464
  }
407
- catch {
408
- const content = await fs.readFile(src, "utf-8");
409
- await fs.writeFile(dest, content);
465
+ if (command === "version") {
466
+ await versionCommand();
467
+ return;
410
468
  }
411
- }
412
- async function main() {
413
- const command = process.argv[2];
414
- switch (command) {
415
- case "onboard":
416
- return await onboard();
417
- case "init":
418
- return await init();
419
- case "doctor":
420
- return await doctor(parseDoctorOptions(process.argv.slice(3)));
421
- case "start":
422
- return await start();
423
- case "help":
424
- default:
425
- return printHelp();
469
+ if (command === "register") {
470
+ await registerCommand(args);
471
+ return;
472
+ }
473
+ if (command === "discover") {
474
+ await discoverCommand(args);
475
+ return;
476
+ }
477
+ if (command === "rotate-key") {
478
+ await rotateKeyCommand(args);
479
+ return;
426
480
  }
481
+ if (command === "intro-events") {
482
+ await introEventsCommand(args);
483
+ return;
484
+ }
485
+ if (command === "mcp-server") {
486
+ await mcpServerCommand(args);
487
+ return;
488
+ }
489
+ if (command === "talent") {
490
+ await talentCommand(args);
491
+ return;
492
+ }
493
+ throw new Error(`Unknown command: ${command}`);
494
+ }
495
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
496
+ runCli().catch((error) => {
497
+ console.error(error instanceof Error ? error.message : String(error));
498
+ process.exit(1);
499
+ });
427
500
  }
428
- main().catch((err) => {
429
- console.error(`\nError: ${err instanceof Error ? err.message : String(err)}`);
430
- if (process.env.DEBUG)
431
- console.error(err);
432
- process.exit(1);
433
- });
434
501
  //# sourceMappingURL=index.js.map