@poping/yome 0.0.2 → 0.0.4

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 (276) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +11 -0
  3. package/README.md +306 -27
  4. package/README.zh-CN.md +333 -0
  5. package/bin/yome-calwatch +0 -0
  6. package/dist/agent.d.ts +24 -2
  7. package/dist/agent.js +34 -2
  8. package/dist/agent.js.map +1 -1
  9. package/dist/context.d.ts +2 -0
  10. package/dist/context.js +121 -13
  11. package/dist/context.js.map +1 -1
  12. package/dist/daemon/calendarPermission.d.ts +10 -0
  13. package/dist/daemon/calendarPermission.js +68 -0
  14. package/dist/daemon/calendarPermission.js.map +1 -0
  15. package/dist/daemon/cronCli.d.ts +19 -0
  16. package/dist/daemon/cronCli.js +403 -0
  17. package/dist/daemon/cronCli.js.map +1 -0
  18. package/dist/daemon/envHint.d.ts +5 -0
  19. package/dist/daemon/envHint.js +139 -0
  20. package/dist/daemon/envHint.js.map +1 -0
  21. package/dist/daemon/humanCron.d.ts +1 -0
  22. package/dist/daemon/humanCron.js +72 -0
  23. package/dist/daemon/humanCron.js.map +1 -0
  24. package/dist/daemon/humanOnce.d.ts +1 -0
  25. package/dist/daemon/humanOnce.js +54 -0
  26. package/dist/daemon/humanOnce.js.map +1 -0
  27. package/dist/daemon/index.d.ts +5 -0
  28. package/dist/daemon/index.js +168 -0
  29. package/dist/daemon/index.js.map +1 -0
  30. package/dist/daemon/launchd.d.ts +7 -0
  31. package/dist/daemon/launchd.js +93 -0
  32. package/dist/daemon/launchd.js.map +1 -0
  33. package/dist/daemon/log.d.ts +17 -0
  34. package/dist/daemon/log.js +57 -0
  35. package/dist/daemon/log.js.map +1 -0
  36. package/dist/daemon/paths.d.ts +11 -0
  37. package/dist/daemon/paths.js +27 -0
  38. package/dist/daemon/paths.js.map +1 -0
  39. package/dist/daemon/runTaskEntry.d.ts +1 -0
  40. package/dist/daemon/runTaskEntry.js +67 -0
  41. package/dist/daemon/runTaskEntry.js.map +1 -0
  42. package/dist/daemon/runner.d.ts +21 -0
  43. package/dist/daemon/runner.js +175 -0
  44. package/dist/daemon/runner.js.map +1 -0
  45. package/dist/daemon/scheduler.d.ts +5 -0
  46. package/dist/daemon/scheduler.js +162 -0
  47. package/dist/daemon/scheduler.js.map +1 -0
  48. package/dist/daemon/taskStore.d.ts +62 -0
  49. package/dist/daemon/taskStore.js +88 -0
  50. package/dist/daemon/taskStore.js.map +1 -0
  51. package/dist/daemon/triggers/calendar.d.ts +8 -0
  52. package/dist/daemon/triggers/calendar.js +248 -0
  53. package/dist/daemon/triggers/calendar.js.map +1 -0
  54. package/dist/daemon/triggers/childRunner.d.ts +14 -0
  55. package/dist/daemon/triggers/childRunner.js +111 -0
  56. package/dist/daemon/triggers/childRunner.js.map +1 -0
  57. package/dist/daemon/triggers/cron.d.ts +14 -0
  58. package/dist/daemon/triggers/cron.js +91 -0
  59. package/dist/daemon/triggers/cron.js.map +1 -0
  60. package/dist/daemon/triggers/file.d.ts +7 -0
  61. package/dist/daemon/triggers/file.js +123 -0
  62. package/dist/daemon/triggers/file.js.map +1 -0
  63. package/dist/daemon/triggers/once.d.ts +10 -0
  64. package/dist/daemon/triggers/once.js +80 -0
  65. package/dist/daemon/triggers/once.js.map +1 -0
  66. package/dist/index.js +240 -15
  67. package/dist/index.js.map +1 -1
  68. package/dist/llm.js +45 -2
  69. package/dist/llm.js.map +1 -1
  70. package/dist/loops/chain.js +8 -0
  71. package/dist/loops/chain.js.map +1 -1
  72. package/dist/loops/evaluator.js +8 -0
  73. package/dist/loops/evaluator.js.map +1 -1
  74. package/dist/loops/orchestrator.js +8 -0
  75. package/dist/loops/orchestrator.js.map +1 -1
  76. package/dist/loops/parallel.js.map +1 -1
  77. package/dist/loops/route.js +8 -0
  78. package/dist/loops/route.js.map +1 -1
  79. package/dist/loops/simple.js +15 -0
  80. package/dist/loops/simple.js.map +1 -1
  81. package/dist/permissions/index.d.ts +1 -1
  82. package/dist/permissions/index.js +1 -1
  83. package/dist/permissions/index.js.map +1 -1
  84. package/dist/permissions/loader.d.ts +20 -1
  85. package/dist/permissions/loader.js +51 -0
  86. package/dist/permissions/loader.js.map +1 -1
  87. package/dist/redact.d.ts +56 -0
  88. package/dist/redact.js +191 -0
  89. package/dist/redact.js.map +1 -0
  90. package/dist/skills/runner/applescript.d.ts +49 -0
  91. package/dist/skills/runner/applescript.js +100 -0
  92. package/dist/skills/runner/applescript.js.map +1 -0
  93. package/dist/skills/runner/dispatcher.d.ts +128 -0
  94. package/dist/skills/runner/dispatcher.js +617 -0
  95. package/dist/skills/runner/dispatcher.js.map +1 -0
  96. package/dist/skills/runner/dispatcher.test.d.ts +1 -0
  97. package/dist/skills/runner/dispatcher.test.js +141 -0
  98. package/dist/skills/runner/dispatcher.test.js.map +1 -0
  99. package/dist/skills/runner/kernel.d.ts +8 -0
  100. package/dist/skills/runner/kernel.js +731 -0
  101. package/dist/skills/runner/kernel.js.map +1 -0
  102. package/dist/skills/runner/nodeBackend.d.ts +32 -0
  103. package/dist/skills/runner/nodeBackend.js +147 -0
  104. package/dist/skills/runner/nodeBackend.js.map +1 -0
  105. package/dist/skills/runner/tokenizer.d.ts +36 -0
  106. package/dist/skills/runner/tokenizer.js +177 -0
  107. package/dist/skills/runner/tokenizer.js.map +1 -0
  108. package/dist/state/todos.d.ts +12 -0
  109. package/dist/state/todos.js +32 -0
  110. package/dist/state/todos.js.map +1 -0
  111. package/dist/threadCli.d.ts +11 -0
  112. package/dist/threadCli.js +177 -0
  113. package/dist/threadCli.js.map +1 -0
  114. package/dist/threadShare.d.ts +21 -0
  115. package/dist/threadShare.js +121 -0
  116. package/dist/threadShare.js.map +1 -0
  117. package/dist/threadSubmit.d.ts +32 -0
  118. package/dist/threadSubmit.js +199 -0
  119. package/dist/threadSubmit.js.map +1 -0
  120. package/dist/tools/askUser.d.ts +20 -0
  121. package/dist/tools/askUser.js +126 -0
  122. package/dist/tools/askUser.js.map +1 -0
  123. package/dist/tools/bash.js +63 -14
  124. package/dist/tools/bash.js.map +1 -1
  125. package/dist/tools/index.d.ts +24 -2
  126. package/dist/tools/index.js +54 -5
  127. package/dist/tools/index.js.map +1 -1
  128. package/dist/tools/skillCall.d.ts +2 -0
  129. package/dist/tools/skillCall.js +77 -0
  130. package/dist/tools/skillCall.js.map +1 -0
  131. package/dist/tools/todoWrite.d.ts +2 -0
  132. package/dist/tools/todoWrite.js +141 -0
  133. package/dist/tools/todoWrite.js.map +1 -0
  134. package/dist/tools/yome.d.ts +2 -0
  135. package/dist/tools/yome.js +87 -0
  136. package/dist/tools/yome.js.map +1 -0
  137. package/dist/ui/AgentPicker.js +3 -3
  138. package/dist/ui/AgentPicker.js.map +1 -1
  139. package/dist/ui/App.js +263 -61
  140. package/dist/ui/App.js.map +1 -1
  141. package/dist/ui/AskUserPrompt.d.ts +7 -0
  142. package/dist/ui/AskUserPrompt.js +78 -0
  143. package/dist/ui/AskUserPrompt.js.map +1 -0
  144. package/dist/ui/Banner.d.ts +2 -1
  145. package/dist/ui/Banner.js +23 -4
  146. package/dist/ui/Banner.js.map +1 -1
  147. package/dist/ui/InputBar.js +25 -36
  148. package/dist/ui/InputBar.js.map +1 -1
  149. package/dist/ui/Markdown.d.ts +2 -2
  150. package/dist/ui/Markdown.js +22 -7
  151. package/dist/ui/Markdown.js.map +1 -1
  152. package/dist/ui/MarketplacePicker.d.ts +7 -0
  153. package/dist/ui/MarketplacePicker.js +122 -0
  154. package/dist/ui/MarketplacePicker.js.map +1 -0
  155. package/dist/ui/MessageList.d.ts +12 -1
  156. package/dist/ui/MessageList.js +72 -7
  157. package/dist/ui/MessageList.js.map +1 -1
  158. package/dist/ui/ModelPicker.js +4 -4
  159. package/dist/ui/ModelPicker.js.map +1 -1
  160. package/dist/ui/MultilineTextInput.d.ts +31 -0
  161. package/dist/ui/MultilineTextInput.js +393 -0
  162. package/dist/ui/MultilineTextInput.js.map +1 -0
  163. package/dist/ui/MultilineTextInput.test.d.ts +1 -0
  164. package/dist/ui/MultilineTextInput.test.js +30 -0
  165. package/dist/ui/MultilineTextInput.test.js.map +1 -0
  166. package/dist/ui/PermissionPrompt.d.ts +16 -4
  167. package/dist/ui/PermissionPrompt.js +60 -15
  168. package/dist/ui/PermissionPrompt.js.map +1 -1
  169. package/dist/ui/SessionPicker.js +2 -2
  170. package/dist/ui/SessionPicker.js.map +1 -1
  171. package/dist/ui/ShimmerText.d.ts +8 -0
  172. package/dist/ui/ShimmerText.js +40 -0
  173. package/dist/ui/ShimmerText.js.map +1 -0
  174. package/dist/ui/Spinner.js +3 -9
  175. package/dist/ui/Spinner.js.map +1 -1
  176. package/dist/ui/TodoPanel.d.ts +7 -0
  177. package/dist/ui/TodoPanel.js +36 -0
  178. package/dist/ui/TodoPanel.js.map +1 -0
  179. package/dist/ui/TogglePicker.js +4 -4
  180. package/dist/ui/TogglePicker.js.map +1 -1
  181. package/dist/ui/ToolResult.js +6 -0
  182. package/dist/ui/ToolResult.js.map +1 -1
  183. package/dist/ui/UnifiedSkillsPicker.d.ts +10 -0
  184. package/dist/ui/UnifiedSkillsPicker.js +63 -0
  185. package/dist/ui/UnifiedSkillsPicker.js.map +1 -0
  186. package/dist/ui/animation.d.ts +3 -0
  187. package/dist/ui/animation.js +48 -0
  188. package/dist/ui/animation.js.map +1 -0
  189. package/dist/ui/useThrottledStream.d.ts +7 -0
  190. package/dist/ui/useThrottledStream.js +63 -0
  191. package/dist/ui/useThrottledStream.js.map +1 -0
  192. package/dist/yomeSkills/auth.d.ts +20 -0
  193. package/dist/yomeSkills/auth.js +70 -0
  194. package/dist/yomeSkills/auth.js.map +1 -0
  195. package/dist/yomeSkills/blacklist.d.ts +33 -0
  196. package/dist/yomeSkills/blacklist.js +101 -0
  197. package/dist/yomeSkills/blacklist.js.map +1 -0
  198. package/dist/yomeSkills/capabilities.d.ts +54 -0
  199. package/dist/yomeSkills/capabilities.js +175 -0
  200. package/dist/yomeSkills/capabilities.js.map +1 -0
  201. package/dist/yomeSkills/capabilityGuard.d.ts +31 -0
  202. package/dist/yomeSkills/capabilityGuard.js +113 -0
  203. package/dist/yomeSkills/capabilityGuard.js.map +1 -0
  204. package/dist/yomeSkills/cli.d.ts +25 -0
  205. package/dist/yomeSkills/cli.js +624 -0
  206. package/dist/yomeSkills/cli.js.map +1 -0
  207. package/dist/yomeSkills/deprecate.d.ts +29 -0
  208. package/dist/yomeSkills/deprecate.js +99 -0
  209. package/dist/yomeSkills/deprecate.js.map +1 -0
  210. package/dist/yomeSkills/devLink.d.ts +17 -0
  211. package/dist/yomeSkills/devLink.js +91 -0
  212. package/dist/yomeSkills/devLink.js.map +1 -0
  213. package/dist/yomeSkills/doctor.d.ts +13 -0
  214. package/dist/yomeSkills/doctor.js +152 -0
  215. package/dist/yomeSkills/doctor.js.map +1 -0
  216. package/dist/yomeSkills/enable.d.ts +8 -0
  217. package/dist/yomeSkills/enable.js +67 -0
  218. package/dist/yomeSkills/enable.js.map +1 -0
  219. package/dist/yomeSkills/hubPing.d.ts +1 -0
  220. package/dist/yomeSkills/hubPing.js +41 -0
  221. package/dist/yomeSkills/hubPing.js.map +1 -0
  222. package/dist/yomeSkills/install.d.ts +18 -0
  223. package/dist/yomeSkills/install.js +143 -0
  224. package/dist/yomeSkills/install.js.map +1 -0
  225. package/dist/yomeSkills/installFromHubTarball.d.ts +26 -0
  226. package/dist/yomeSkills/installFromHubTarball.js +161 -0
  227. package/dist/yomeSkills/installFromHubTarball.js.map +1 -0
  228. package/dist/yomeSkills/installGithub.d.ts +33 -0
  229. package/dist/yomeSkills/installGithub.js +213 -0
  230. package/dist/yomeSkills/installGithub.js.map +1 -0
  231. package/dist/yomeSkills/installMeta.d.ts +8 -0
  232. package/dist/yomeSkills/installMeta.js +76 -0
  233. package/dist/yomeSkills/installMeta.js.map +1 -0
  234. package/dist/yomeSkills/integrity.d.ts +26 -0
  235. package/dist/yomeSkills/integrity.js +107 -0
  236. package/dist/yomeSkills/integrity.js.map +1 -0
  237. package/dist/yomeSkills/invoke.d.ts +29 -0
  238. package/dist/yomeSkills/invoke.js +135 -0
  239. package/dist/yomeSkills/invoke.js.map +1 -0
  240. package/dist/yomeSkills/list.d.ts +11 -0
  241. package/dist/yomeSkills/list.js +55 -0
  242. package/dist/yomeSkills/list.js.map +1 -0
  243. package/dist/yomeSkills/login.d.ts +41 -0
  244. package/dist/yomeSkills/login.js +221 -0
  245. package/dist/yomeSkills/login.js.map +1 -0
  246. package/dist/yomeSkills/manifest.d.ts +60 -0
  247. package/dist/yomeSkills/manifest.js +47 -0
  248. package/dist/yomeSkills/manifest.js.map +1 -0
  249. package/dist/yomeSkills/paths.d.ts +13 -0
  250. package/dist/yomeSkills/paths.js +33 -0
  251. package/dist/yomeSkills/paths.js.map +1 -0
  252. package/dist/yomeSkills/publish.d.ts +18 -0
  253. package/dist/yomeSkills/publish.js +114 -0
  254. package/dist/yomeSkills/publish.js.map +1 -0
  255. package/dist/yomeSkills/rollback.d.ts +10 -0
  256. package/dist/yomeSkills/rollback.js +83 -0
  257. package/dist/yomeSkills/rollback.js.map +1 -0
  258. package/dist/yomeSkills/search.d.ts +21 -0
  259. package/dist/yomeSkills/search.js +31 -0
  260. package/dist/yomeSkills/search.js.map +1 -0
  261. package/dist/yomeSkills/skillsIndex.d.ts +36 -0
  262. package/dist/yomeSkills/skillsIndex.js +111 -0
  263. package/dist/yomeSkills/skillsIndex.js.map +1 -0
  264. package/dist/yomeSkills/unified.d.ts +53 -0
  265. package/dist/yomeSkills/unified.js +187 -0
  266. package/dist/yomeSkills/unified.js.map +1 -0
  267. package/dist/yomeSkills/uninstall.d.ts +7 -0
  268. package/dist/yomeSkills/uninstall.js +22 -0
  269. package/dist/yomeSkills/uninstall.js.map +1 -0
  270. package/dist/yomeSkills/update.d.ts +18 -0
  271. package/dist/yomeSkills/update.js +75 -0
  272. package/dist/yomeSkills/update.js.map +1 -0
  273. package/dist/yomeSkills/validate.d.ts +11 -0
  274. package/dist/yomeSkills/validate.js +99 -0
  275. package/dist/yomeSkills/validate.js.map +1 -0
  276. package/package.json +23 -6
@@ -0,0 +1,221 @@
1
+ // `yome login` — provider-agnostic Yome login.
2
+ //
3
+ // Yome's identity model: user accounts live in Supabase (auth.users); GitHub
4
+ // (and later Apple, WeChat, email) are *providers* attached to that account.
5
+ // The CLI cannot hold a Supabase session directly, so the flow is:
6
+ //
7
+ // 1. Run a provider-specific browser login (currently only GitHub Device
8
+ // Flow).
9
+ // 2. Take the provider token (e.g. GitHub access_token), POST it to
10
+ // /api/cli/auth/exchange. The hub:
11
+ // a. verifies the provider token with the provider,
12
+ // b. looks up the matching Yome user (must already exist — i.e.
13
+ // the user must have logged in on the website at least once),
14
+ // c. mints a fresh opaque "yome_token" tied to the Yome user_id.
15
+ // 3. Persist {yome_token, yome_user_id, provider, …} to ~/.yome/auth.json.
16
+ //
17
+ // All future hub calls (publish, install metrics, …) use the yome_token,
18
+ // never the GitHub token. The GitHub token never touches disk.
19
+ //
20
+ // All network calls accept a `fetcher` argument so tests can mock them
21
+ // without monkey-patching globalThis.
22
+ import { writeAuthState } from './auth.js';
23
+ const GITHUB_DEVICE_CODE_URL = 'https://github.com/login/device/code';
24
+ const GITHUB_TOKEN_URL = 'https://github.com/login/oauth/access_token';
25
+ // Public OAuth App client_id for the "Yome" GitHub App. Same App as the
26
+ // website (Web Flow callback to /auth/github/callback) — Device Flow is
27
+ // enabled on the same App, so CLI + browser login share one identity.
28
+ // Client IDs are NOT secrets; safe to bake into the published CLI.
29
+ const DEFAULT_CLIENT_ID = 'Ov23li25VzpbbfedkWOB';
30
+ const DEFAULT_SCOPES = 'read:user';
31
+ const DEFAULT_HUB_BASE = 'https://yome.work';
32
+ export function getClientId() {
33
+ return process.env.YOME_GITHUB_CLIENT_ID || DEFAULT_CLIENT_ID;
34
+ }
35
+ export function getHubBase() {
36
+ return process.env.YOME_HUB_BASE || DEFAULT_HUB_BASE;
37
+ }
38
+ // Default fetcher.
39
+ //
40
+ // Node's bundled undici defaults to a 10-second `connectTimeout` which
41
+ // is unrealistic for GitHub from networks with high TLS-handshake
42
+ // latency (notably mainland China). We install a long-timeout dispatcher
43
+ // so that `fetch()` won't abort during the TLS handshake.
44
+ //
45
+ // We use a dynamic import of undici from the Node internals; if for any
46
+ // reason that fails (e.g. we're on a runtime without undici) we just
47
+ // fall back to the bare fetch and rely on the request-side AbortController.
48
+ let _patchedAgent;
49
+ async function getDispatcher() {
50
+ if (_patchedAgent !== undefined)
51
+ return _patchedAgent ?? null;
52
+ try {
53
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
54
+ // @ts-ignore: built-in module not typed in lib
55
+ const undici = await import('node:undici').catch(() => null) ?? await import('undici').catch(() => null);
56
+ if (!undici || !undici.Agent) {
57
+ _patchedAgent = null;
58
+ return null;
59
+ }
60
+ const Agent = undici.Agent;
61
+ _patchedAgent = new Agent({
62
+ connect: { timeout: 60_000 },
63
+ headersTimeout: 60_000,
64
+ bodyTimeout: 60_000,
65
+ });
66
+ return _patchedAgent;
67
+ }
68
+ catch {
69
+ _patchedAgent = null;
70
+ return null;
71
+ }
72
+ }
73
+ const realFetcher = async (url, init) => {
74
+ // Per-call AbortController as belt-and-braces. `dispatcher` is the
75
+ // primary remedy (controls TLS-handshake time); the controller catches
76
+ // anything that slips past.
77
+ const controller = new AbortController();
78
+ const t = setTimeout(() => controller.abort(), 90_000);
79
+ const dispatcher = await getDispatcher();
80
+ const finalInit = {
81
+ ...init,
82
+ signal: controller.signal,
83
+ // Add the dispatcher only when undici is available; fetch will
84
+ // ignore unknown keys when running on plain node.
85
+ ...(dispatcher ? { dispatcher } : {}),
86
+ };
87
+ try {
88
+ return await fetch(url, finalInit);
89
+ }
90
+ finally {
91
+ clearTimeout(t);
92
+ }
93
+ };
94
+ export async function performLogin(opts = {}) {
95
+ const clientId = opts.clientId ?? getClientId();
96
+ const scopes = opts.scopes ?? DEFAULT_SCOPES;
97
+ const fetcher = opts.fetcher ?? realFetcher;
98
+ const sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
99
+ const timeoutMs = opts.timeoutMs ?? 600_000;
100
+ const hubBase = (opts.hubBase ?? getHubBase()).replace(/\/+$/, '');
101
+ if (!clientId || clientId.startsWith('Iv1.PLACEHOLDER')) {
102
+ return {
103
+ ok: false,
104
+ code: 'no_client_id',
105
+ reason: 'YOME_GITHUB_CLIENT_ID is not configured. Ask a yome.work maintainer for the OAuth App client_id and re-run with that env var set.',
106
+ };
107
+ }
108
+ // ── Phase 1 — GitHub Device Flow → ephemeral GitHub token ──────────
109
+ const dcResp = await fetcher(GITHUB_DEVICE_CODE_URL, {
110
+ method: 'POST',
111
+ headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
112
+ body: JSON.stringify({ client_id: clientId, scope: scopes }),
113
+ });
114
+ if (!dcResp.ok) {
115
+ return { ok: false, code: 'github_failed', reason: `device_code request failed: HTTP ${dcResp.status}` };
116
+ }
117
+ const dc = (await dcResp.json());
118
+ if (!dc.user_code || !dc.device_code) {
119
+ return { ok: false, code: 'github_failed', reason: 'device_code response missing fields' };
120
+ }
121
+ if (opts.onPrompt)
122
+ opts.onPrompt(dc);
123
+ else
124
+ printPrompt(dc);
125
+ let githubToken = null;
126
+ const start = Date.now();
127
+ let intervalMs = (opts.pollIntervalMs ?? dc.interval * 1000) || 5000;
128
+ while (Date.now() - start < timeoutMs) {
129
+ await sleep(intervalMs);
130
+ const tResp = await fetcher(GITHUB_TOKEN_URL, {
131
+ method: 'POST',
132
+ headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
133
+ body: JSON.stringify({
134
+ client_id: clientId,
135
+ device_code: dc.device_code,
136
+ grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
137
+ }),
138
+ });
139
+ if (!tResp.ok)
140
+ continue;
141
+ const tok = (await tResp.json());
142
+ if (tok.access_token) {
143
+ githubToken = tok.access_token;
144
+ break;
145
+ }
146
+ if (tok.error === 'authorization_pending')
147
+ continue;
148
+ if (tok.error === 'slow_down') {
149
+ intervalMs += 5000;
150
+ continue;
151
+ }
152
+ if (tok.error === 'access_denied')
153
+ return { ok: false, code: 'user_denied', reason: 'user denied authorisation' };
154
+ if (tok.error === 'expired_token')
155
+ return { ok: false, code: 'expired', reason: 'device code expired before authorisation' };
156
+ return { ok: false, code: 'github_failed', reason: tok.error_description || tok.error || 'unknown token error' };
157
+ }
158
+ if (!githubToken)
159
+ return { ok: false, code: 'timeout', reason: 'timed out waiting for authorisation' };
160
+ // ── Phase 2 — exchange GitHub token for a Yome CLI token ───────────
161
+ const exResp = await fetcher(`${hubBase}/api/cli/auth/exchange`, {
162
+ method: 'POST',
163
+ headers: { 'Content-Type': 'application/json' },
164
+ body: JSON.stringify({
165
+ provider: 'github',
166
+ github_token: githubToken,
167
+ client_label: defaultClientLabel(),
168
+ }),
169
+ });
170
+ let exJson;
171
+ try {
172
+ exJson = (await exResp.json());
173
+ }
174
+ catch {
175
+ return { ok: false, code: 'network', reason: `exchange returned non-JSON (HTTP ${exResp.status})` };
176
+ }
177
+ if (!exResp.ok || !exJson.ok || !exJson.yome_token || !exJson.user_id) {
178
+ if (exJson.code === 'yome_user_not_found') {
179
+ return {
180
+ ok: false,
181
+ code: 'yome_user_not_found',
182
+ reason: exJson.error ?? 'GitHub account is not linked to a Yome account yet — please sign in once at https://yome.work to link.',
183
+ };
184
+ }
185
+ return {
186
+ ok: false,
187
+ code: 'exchange_failed',
188
+ reason: exJson.error ?? `exchange failed: HTTP ${exResp.status}`,
189
+ };
190
+ }
191
+ const state = {
192
+ yome_token: exJson.yome_token,
193
+ yome_user_id: exJson.user_id,
194
+ provider: 'github',
195
+ provider_login: exJson.login,
196
+ expires_at: exJson.expires_at ?? '',
197
+ obtained_at: new Date().toISOString(),
198
+ };
199
+ writeAuthState(state);
200
+ return { ok: true, state };
201
+ }
202
+ function printPrompt(dc) {
203
+ console.log('');
204
+ console.log(' ─── GitHub authorisation required ───');
205
+ console.log(` Open: ${dc.verification_uri}`);
206
+ console.log(` Code: ${dc.user_code}`);
207
+ console.log(` (Code expires in ${Math.round(dc.expires_in / 60)} minutes)`);
208
+ console.log('');
209
+ console.log('Waiting for you to authorise…');
210
+ }
211
+ function defaultClientLabel() {
212
+ // "yome-cli on darwin" → cheap human-readable hint for the future
213
+ // "active sessions" panel on the website. Not security-critical.
214
+ try {
215
+ return `yome-cli on ${process.platform}`;
216
+ }
217
+ catch {
218
+ return 'yome-cli';
219
+ }
220
+ }
221
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/yomeSkills/login.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ export interface SkillCommandSummary {
2
+ action: string;
3
+ desc?: string;
4
+ since?: string;
5
+ }
6
+ export interface SkillManifest {
7
+ schemaVersion?: number;
8
+ slug: string;
9
+ name?: string;
10
+ description?: string;
11
+ domain: string;
12
+ version: string;
13
+ official?: boolean;
14
+ homepage?: string;
15
+ repo?: string;
16
+ /**
17
+ * Structured L1 documentation — what the LLM sees in its system prompt
18
+ * for this skill. Three short fields, each one-line, each answers one
19
+ * specific question the model has when deciding whether to invoke:
20
+ *
21
+ * when — "user wants to ..." (the trigger condition)
22
+ * entry — first command to discover the rest (typically `<domain> --help`)
23
+ * effects — truthful side-effects so the model can warn / batch correctly
24
+ *
25
+ * Renderer (cli/src/context.ts → buildHubSkillsSection) emits a 3-row
26
+ * pipe-aligned block; if l1 is absent we fall back to `prompt_line`,
27
+ * then to `<domain> — <description>`.
28
+ */
29
+ l1?: {
30
+ when?: string;
31
+ entry?: string;
32
+ effects?: string;
33
+ };
34
+ /**
35
+ * Legacy single-line "elevator pitch". Used only as a fallback when
36
+ * `l1` is not provided. New skills should prefer `l1`.
37
+ */
38
+ prompt_line?: string;
39
+ platforms?: string[];
40
+ delivery?: Record<string, unknown>;
41
+ capabilities?: string[];
42
+ /** OS-level resources the skill needs (M9 security model). One of:
43
+ * fs:read, fs:write, fs:delete, applescript, network, shell. */
44
+ system_capabilities?: string[];
45
+ tags?: string[];
46
+ license?: string;
47
+ author?: {
48
+ name?: string;
49
+ email?: string;
50
+ github?: string;
51
+ };
52
+ commands?: SkillCommandSummary[];
53
+ }
54
+ export declare function readManifest(skillDir: string): SkillManifest | null;
55
+ export interface ValidationResult {
56
+ ok: boolean;
57
+ errors: string[];
58
+ }
59
+ /** Validate just enough to safely install. Schema-level checks are out of scope. */
60
+ export declare function validateManifest(m: SkillManifest): ValidationResult;
@@ -0,0 +1,47 @@
1
+ // Light-weight yome-skill.json reader. We don't bring in a JSON-Schema
2
+ // validator because that would pull ajv (~50KB) into the CLI install size
3
+ // for one validation. Instead we hand-check the few invariants the runtime
4
+ // actually depends on: slug shape, version semver, domain identifier.
5
+ import { readFileSync, existsSync } from 'fs';
6
+ import { join } from 'path';
7
+ const SLUG_RE = /^@[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
8
+ const SEMVER_RE = /^\d+\.\d+\.\d+(?:-[A-Za-z0-9.-]+)?$/;
9
+ const DOMAIN_RE = /^[a-z][a-z0-9_]*$/;
10
+ export function readManifest(skillDir) {
11
+ const path = join(skillDir, 'yome-skill.json');
12
+ if (!existsSync(path))
13
+ return null;
14
+ let raw;
15
+ try {
16
+ raw = readFileSync(path, 'utf-8');
17
+ }
18
+ catch {
19
+ return null;
20
+ }
21
+ let data;
22
+ try {
23
+ data = JSON.parse(raw);
24
+ }
25
+ catch {
26
+ return null;
27
+ }
28
+ if (typeof data !== 'object' || data == null)
29
+ return null;
30
+ const m = data;
31
+ if (typeof m.slug !== 'string' || typeof m.domain !== 'string' || typeof m.version !== 'string') {
32
+ return null;
33
+ }
34
+ return m;
35
+ }
36
+ /** Validate just enough to safely install. Schema-level checks are out of scope. */
37
+ export function validateManifest(m) {
38
+ const errors = [];
39
+ if (!SLUG_RE.test(m.slug))
40
+ errors.push(`invalid slug "${m.slug}" (expected @<owner>/<name>)`);
41
+ if (!DOMAIN_RE.test(m.domain))
42
+ errors.push(`invalid domain "${m.domain}"`);
43
+ if (!SEMVER_RE.test(m.version))
44
+ errors.push(`invalid version "${m.version}" (expected x.y.z)`);
45
+ return { ok: errors.length === 0, errors };
46
+ }
47
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/yomeSkills/manifest.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,0EAA0E;AAC1E,2EAA2E;AAC3E,sEAAsE;AAEtE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAsD5B,MAAM,OAAO,GAAG,qCAAqC,CAAC;AACtD,MAAM,SAAS,GAAG,qCAAqC,CAAC;AACxD,MAAM,SAAS,GAAG,mBAAmB,CAAC;AAEtC,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAAC;IAC/C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IAC1D,MAAM,CAAC,GAAG,IAA+B,CAAC;IAC1C,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QAChG,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,CAA6B,CAAC;AACvC,CAAC;AAOD,oFAAoF;AACpF,MAAM,UAAU,gBAAgB,CAAC,CAAgB;IAC/C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,IAAI,8BAA8B,CAAC,CAAC;IAC9F,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IAC3E,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,OAAO,oBAAoB,CAAC,CAAC;IAC/F,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;AAC7C,CAAC"}
@@ -0,0 +1,13 @@
1
+ /** ~/.yome/skills */
2
+ export declare function getYomeSkillsRoot(): string;
3
+ /**
4
+ * Parse @<owner>/<name> into install path components. Returns null if the
5
+ * slug shape is wrong; callers should treat that as a CLI argument error.
6
+ */
7
+ export declare function parseSlug(slug: string): {
8
+ owner: string;
9
+ name: string;
10
+ full: string;
11
+ } | null;
12
+ /** Installed location for a given slug: ~/.yome/skills/<owner>/<name>/ */
13
+ export declare function installPathForSlug(slug: string): string | null;
@@ -0,0 +1,33 @@
1
+ // Path conventions for the yome-skill.json system (spec 4 / spec 8.5).
2
+ //
3
+ // We reuse ~/.yome/skills/ — the same directory the legacy markdown
4
+ // SKILL.md system already uses — and disambiguate by manifest file:
5
+ // <yomeSkillsRoot>/<owner>/<name>/yome-skill.json ← spec-style (this module)
6
+ // <yomeSkillsRoot>/<some-folder>/SKILL.md ← legacy markdown skill
7
+ // Both can coexist; loaders ignore directories without their expected manifest.
8
+ import { homedir } from 'os';
9
+ import { join } from 'path';
10
+ /** ~/.yome/skills */
11
+ export function getYomeSkillsRoot() {
12
+ return join(homedir(), '.yome', 'skills');
13
+ }
14
+ /**
15
+ * Parse @<owner>/<name> into install path components. Returns null if the
16
+ * slug shape is wrong; callers should treat that as a CLI argument error.
17
+ */
18
+ export function parseSlug(slug) {
19
+ const m = /^@([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)$/.exec(slug);
20
+ if (!m)
21
+ return null;
22
+ const owner = m[1];
23
+ const name = m[2];
24
+ return { owner, name, full: `@${owner}/${name}` };
25
+ }
26
+ /** Installed location for a given slug: ~/.yome/skills/<owner>/<name>/ */
27
+ export function installPathForSlug(slug) {
28
+ const p = parseSlug(slug);
29
+ if (!p)
30
+ return null;
31
+ return join(getYomeSkillsRoot(), p.owner, p.name);
32
+ }
33
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/yomeSkills/paths.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,EAAE;AACF,oEAAoE;AACpE,oEAAoE;AACpE,iFAAiF;AACjF,+EAA+E;AAC/E,gFAAgF;AAEhF,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,qBAAqB;AACrB,MAAM,UAAU,iBAAiB;IAC/B,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;AAC5C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,MAAM,CAAC,GAAG,yCAAyC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/D,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACnB,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAClB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,IAAI,EAAE,EAAE,CAAC;AACpD,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,MAAM,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC1B,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,OAAO,IAAI,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AACpD,CAAC"}
@@ -0,0 +1,18 @@
1
+ export interface PublishOptions {
2
+ /** Override hub base URL (default = YOME_HUB_BASE or https://yome.work). */
3
+ hubBase?: string;
4
+ /** Skip clean-tree + git remote checks (use --force). */
5
+ force?: boolean;
6
+ /** Test seam — replaces global fetch. */
7
+ fetcher?: typeof fetch;
8
+ }
9
+ export interface PublishResult {
10
+ ok: boolean;
11
+ slug?: string;
12
+ version?: string;
13
+ /** 'created' for a brand-new version row, 'noop_same_sha' for an idempotent re-publish. */
14
+ outcome?: 'created' | 'noop_same_sha';
15
+ hubResponse?: unknown;
16
+ reason?: string;
17
+ }
18
+ export declare function publishSkill(cwd: string, opts?: PublishOptions): Promise<PublishResult>;
@@ -0,0 +1,114 @@
1
+ // `yome skill publish` — notify the hub about a new version of a skill
2
+ // you maintain. Path A only (no tarball upload yet, no esbuild bundle).
3
+ //
4
+ // Pre-conditions:
5
+ // - cwd contains a valid yome-skill.json
6
+ // - cwd is a git repo with a github.com remote
7
+ // - working tree is clean (no uncommitted changes)
8
+ // - you are logged in (`yome login`) — we send the auth token to hub
9
+ //
10
+ // On success the hub upserts hub_skills (slug → repo) and inserts a
11
+ // hub_skill_versions row at manifest.version. The hub end of this is
12
+ // /api/hub/skills/<slug>/publish.
13
+ import { existsSync, statSync } from 'fs';
14
+ import { spawnSync } from 'node:child_process';
15
+ import { resolve } from 'path';
16
+ import { readManifest, validateManifest } from './manifest.js';
17
+ import { readAuthState } from './auth.js';
18
+ import { computeSkillSha256 } from './integrity.js';
19
+ const DEFAULT_HUB_BASE = 'https://yome.work';
20
+ export async function publishSkill(cwd, opts = {}) {
21
+ const abs = resolve(cwd);
22
+ if (!existsSync(abs) || !statSync(abs).isDirectory()) {
23
+ return { ok: false, reason: `cwd is not a directory: ${abs}` };
24
+ }
25
+ const manifest = readManifest(abs);
26
+ if (!manifest)
27
+ return { ok: false, reason: `${abs}/yome-skill.json missing or unreadable` };
28
+ const v = validateManifest(manifest);
29
+ if (!v.ok)
30
+ return { ok: false, reason: `manifest invalid: ${v.errors.join('; ')}` };
31
+ const auth = readAuthState();
32
+ if (!auth)
33
+ return { ok: false, reason: 'not logged in — run `yome login` first' };
34
+ const gitInfo = inspectGit(abs);
35
+ if (!gitInfo.ok && !opts.force)
36
+ return { ok: false, reason: gitInfo.reason };
37
+ const hubBase = (opts.hubBase ?? process.env.YOME_HUB_BASE ?? DEFAULT_HUB_BASE).replace(/\/$/, '');
38
+ const url = `${hubBase}/api/hub/skills/${encodeURIComponent(manifest.slug)}/publish`;
39
+ const body = buildPublishBody(manifest, gitInfo, abs);
40
+ const fetcher = opts.fetcher ?? fetch;
41
+ let resp;
42
+ try {
43
+ resp = await fetcher(url, {
44
+ method: 'POST',
45
+ headers: {
46
+ 'Content-Type': 'application/json',
47
+ Authorization: `Bearer ${auth.yome_token}`,
48
+ 'User-Agent': 'yome-cli/0.1',
49
+ },
50
+ body: JSON.stringify(body),
51
+ });
52
+ }
53
+ catch (e) {
54
+ return { ok: false, reason: `publish request failed: ${e.message}` };
55
+ }
56
+ let parsed;
57
+ try {
58
+ parsed = await resp.json();
59
+ }
60
+ catch {
61
+ parsed = null;
62
+ }
63
+ if (!resp.ok) {
64
+ const reason = parsed && typeof parsed === 'object' && 'error' in parsed
65
+ ? String(parsed.error) : `HTTP ${resp.status}`;
66
+ return { ok: false, reason: `hub rejected publish: ${reason}` };
67
+ }
68
+ const outcome = parsed && typeof parsed === 'object' && 'outcome' in parsed
69
+ ? (parsed.outcome === 'noop_same_sha'
70
+ ? 'noop_same_sha'
71
+ : 'created')
72
+ : 'created';
73
+ return { ok: true, slug: manifest.slug, version: manifest.version, outcome, hubResponse: parsed };
74
+ }
75
+ function inspectGit(cwd) {
76
+ const probe = spawnSync('git', ['-C', cwd, 'rev-parse', '--is-inside-work-tree'], { encoding: 'utf-8' });
77
+ if (probe.status !== 0)
78
+ return { ok: false, reason: 'cwd is not a git repo' };
79
+ const remoteRes = spawnSync('git', ['-C', cwd, 'config', '--get', 'remote.origin.url'], { encoding: 'utf-8' });
80
+ if (remoteRes.status !== 0)
81
+ return { ok: false, reason: 'no remote.origin.url configured' };
82
+ const remote = remoteRes.stdout.trim();
83
+ const fullName = parseGithubFullName(remote);
84
+ if (!fullName)
85
+ return { ok: false, reason: `origin remote is not GitHub: ${remote}` };
86
+ const branchRes = spawnSync('git', ['-C', cwd, 'rev-parse', '--abbrev-ref', 'HEAD'], { encoding: 'utf-8' });
87
+ const branch = branchRes.status === 0 ? branchRes.stdout.trim() : 'main';
88
+ const shaRes = spawnSync('git', ['-C', cwd, 'rev-parse', 'HEAD'], { encoding: 'utf-8' });
89
+ const sha = shaRes.status === 0 ? shaRes.stdout.trim() : '';
90
+ const dirtyRes = spawnSync('git', ['-C', cwd, 'status', '--porcelain'], { encoding: 'utf-8' });
91
+ const isClean = dirtyRes.status === 0 && dirtyRes.stdout.trim().length === 0;
92
+ if (!isClean)
93
+ return { ok: false, reason: 'working tree is dirty (commit or stash before publishing, or use --force)', remote, fullName, branch, sha, isClean };
94
+ return { ok: true, remote, fullName, branch, sha, isClean };
95
+ }
96
+ function parseGithubFullName(s) {
97
+ const m = s.match(/github\.com[\/:]([\w.-]+\/[\w.-]+?)(?:\.git)?(?:\/|$)/);
98
+ return m ? m[1] : null;
99
+ }
100
+ function buildPublishBody(m, g, cwd) {
101
+ return {
102
+ slug: m.slug,
103
+ version: m.version,
104
+ domain: m.domain,
105
+ name: m.name ?? null,
106
+ description: m.description ?? null,
107
+ capabilities: m.capabilities ?? null,
108
+ github_full_name: g.fullName ?? null,
109
+ github_default_branch: g.branch ?? 'main',
110
+ git_sha: g.sha ?? null,
111
+ tarball_sha256: computeSkillSha256(cwd),
112
+ };
113
+ }
114
+ //# sourceMappingURL=publish.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish.js","sourceRoot":"","sources":["../../src/yomeSkills/publish.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,wEAAwE;AACxE,EAAE;AACF,kBAAkB;AAClB,2CAA2C;AAC3C,iDAAiD;AACjD,qDAAqD;AACrD,uEAAuE;AACvE,EAAE;AACF,oEAAoE;AACpE,qEAAqE;AACrE,kCAAkC;AAElC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAsB,MAAM,eAAe,CAAC;AACnF,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAqBpD,MAAM,gBAAgB,GAAG,mBAAmB,CAAC;AAE7C,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAW,EAAE,OAAuB,EAAE;IACvE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IACzB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;QACrD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,2BAA2B,GAAG,EAAE,EAAE,CAAC;IACjE,CAAC;IACD,MAAM,QAAQ,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,GAAG,wCAAwC,EAAE,CAAC;IAC5F,MAAM,CAAC,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IACrC,IAAI,CAAC,CAAC,CAAC,EAAE;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,qBAAqB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;IAEpF,MAAM,IAAI,GAAG,aAAa,EAAE,CAAC;IAC7B,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,wCAAwC,EAAE,CAAC;IAElF,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;IAE7E,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,gBAAgB,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACnG,MAAM,GAAG,GAAG,GAAG,OAAO,mBAAmB,kBAAkB,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC;IACrF,MAAM,IAAI,GAAG,gBAAgB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;IAEtD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC;IACtC,IAAI,IAAI,CAAC;IACT,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE;YACxB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,aAAa,EAAE,UAAU,IAAI,CAAC,UAAU,EAAE;gBAC1C,YAAY,EAAE,cAAc;aAC7B;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,2BAA4B,CAAW,CAAC,OAAO,EAAE,EAAE,CAAC;IAClF,CAAC;IACD,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QAAC,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,MAAM,GAAG,IAAI,CAAC;IAAC,CAAC;IAC5D,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,OAAO,IAAI,MAAM;YACtE,CAAC,CAAC,MAAM,CAAE,MAA6B,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;QACzE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,yBAAyB,MAAM,EAAE,EAAE,CAAC;IAClE,CAAC;IACD,MAAM,OAAO,GACX,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,SAAS,IAAI,MAAM;QACzD,CAAC,CAAC,CAAE,MAA+B,CAAC,OAAO,KAAK,eAAe;YAC3D,CAAC,CAAC,eAAe;YACjB,CAAC,CAAC,SAAS,CAAC;QAChB,CAAC,CAAC,SAAS,CAAC;IAChB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;AACpG,CAAC;AAYD,SAAS,UAAU,CAAC,GAAW;IAC7B,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,WAAW,EAAE,uBAAuB,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IACzG,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,uBAAuB,EAAE,CAAC;IAE9E,MAAM,SAAS,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,mBAAmB,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IAC/G,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,iCAAiC,EAAE,CAAC;IAC5F,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IACvC,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC7C,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,gCAAgC,MAAM,EAAE,EAAE,CAAC;IAEtF,MAAM,SAAS,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IAC5G,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IAEzE,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IACzF,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAE5D,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,aAAa,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IAC/F,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,CAAC;IAC7E,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,2EAA2E,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC;IAEhK,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC;AAC9D,CAAC;AAED,SAAS,mBAAmB,CAAC,CAAS;IACpC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,uDAAuD,CAAC,CAAC;IAC3E,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACzB,CAAC;AAgBD,SAAS,gBAAgB,CAAC,CAAgB,EAAE,CAAa,EAAE,GAAW;IACpE,OAAO;QACL,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,IAAI;QACpB,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,IAAI;QAClC,YAAY,EAAE,CAAC,CAAC,YAAY,IAAI,IAAI;QACpC,gBAAgB,EAAE,CAAC,CAAC,QAAQ,IAAI,IAAI;QACpC,qBAAqB,EAAE,CAAC,CAAC,MAAM,IAAI,MAAM;QACzC,OAAO,EAAE,CAAC,CAAC,GAAG,IAAI,IAAI;QACtB,cAAc,EAAE,kBAAkB,CAAC,GAAG,CAAC;KACxC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,10 @@
1
+ export interface RollbackResult {
2
+ ok: boolean;
3
+ slug?: string;
4
+ /** Version we rolled back TO (read from the restored manifest). */
5
+ restoredVersion?: string;
6
+ /** Version we rolled back FROM. */
7
+ previousVersion?: string;
8
+ reason?: string;
9
+ }
10
+ export declare function rollbackBySlug(slug: string): Promise<RollbackResult>;
@@ -0,0 +1,83 @@
1
+ // `yome skill rollback <slug>` — swap back to the previous version.
2
+ //
3
+ // Spec 11.4-D requires "保留最近 2 个版本目录" — we keep one snapshot
4
+ // (`<slug-dir>.previous/`) created by `install.ts` whenever it overwrites
5
+ // an existing install. This module performs the atomic swap:
6
+ //
7
+ // live : ~/.yome/skills/<owner>/<name> (current)
8
+ // prev : ~/.yome/skills/<owner>/<name>.previous (last good)
9
+ //
10
+ // rollback:
11
+ // prev → swap-tmp → live (i.e. live becomes previous, previous becomes live)
12
+ //
13
+ // After rollback the swap-tmp now holds what was live; we move it to the
14
+ // `.previous` slot so the user can also rollback the rollback (one level
15
+ // of undo, capped to keep disk usage bounded).
16
+ //
17
+ // Edge cases:
18
+ // - No `.previous` snapshot present → tell the user, exit cleanly.
19
+ // - Live install was uninstalled (no live dir) → restore previous in place.
20
+ // - Allowed-capabilities sidecar lives INSIDE the install dir, so it
21
+ // swaps with the rest. No extra work needed.
22
+ // - Index cache may now be stale → we refresh it.
23
+ import { existsSync, renameSync, rmSync, mkdirSync } from 'fs';
24
+ import { dirname } from 'path';
25
+ import { installPathForSlug } from './paths.js';
26
+ import { readManifest } from './manifest.js';
27
+ import { refreshIndex } from './skillsIndex.js';
28
+ export async function rollbackBySlug(slug) {
29
+ const live = installPathForSlug(slug);
30
+ if (!live)
31
+ return { ok: false, reason: `bad slug: ${slug}` };
32
+ const snap = `${live}.previous`;
33
+ if (!existsSync(snap)) {
34
+ return { ok: false, reason: `no rollback snapshot for ${slug} — nothing to roll back to` };
35
+ }
36
+ // Capture versions for the report (best-effort; manifest read is cheap).
37
+ const liveManifest = existsSync(live) ? readManifest(live) : null;
38
+ const prevManifest = readManifest(snap);
39
+ const previousVersion = liveManifest?.version;
40
+ const restoredVersion = prevManifest?.version;
41
+ // Atomic-ish swap. We need a temporary intermediate name because
42
+ // renameSync(live, snap) when snap already exists is destructive on POSIX.
43
+ // Sequence:
44
+ // 1. live → tmp
45
+ // 2. snap → live
46
+ // 3. tmp → snap (overwrite-protected: we rmSync first if it exists,
47
+ // though step 2 just moved it away)
48
+ const tmp = `${live}.swap-${process.pid}-${Date.now()}`;
49
+ try {
50
+ if (existsSync(live)) {
51
+ mkdirSync(dirname(live), { recursive: true });
52
+ renameSync(live, tmp);
53
+ }
54
+ renameSync(snap, live);
55
+ if (existsSync(tmp)) {
56
+ // step 3: archive what was live as the new previous
57
+ if (existsSync(snap))
58
+ rmSync(snap, { recursive: true, force: true });
59
+ renameSync(tmp, snap);
60
+ }
61
+ }
62
+ catch (err) {
63
+ // Best-effort recovery: try to put live back if we moved it but failed
64
+ // to install snap. Don't pretend everything is fine.
65
+ try {
66
+ if (existsSync(tmp) && !existsSync(live))
67
+ renameSync(tmp, live);
68
+ }
69
+ catch { /* ignore */ }
70
+ return { ok: false, slug, reason: `rename failed during rollback: ${err.message}` };
71
+ }
72
+ try {
73
+ refreshIndex();
74
+ }
75
+ catch { /* best effort */ }
76
+ return {
77
+ ok: true,
78
+ slug,
79
+ restoredVersion,
80
+ previousVersion,
81
+ };
82
+ }
83
+ //# sourceMappingURL=rollback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rollback.js","sourceRoot":"","sources":["../../src/yomeSkills/rollback.ts"],"names":[],"mappings":"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"}