@digitalpresence/cliclaw 0.1.0

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 (338) hide show
  1. package/dist/__tests__/calendar.integration.test.d.ts +2 -0
  2. package/dist/__tests__/calendar.integration.test.d.ts.map +1 -0
  3. package/dist/__tests__/calendar.integration.test.js +98 -0
  4. package/dist/__tests__/calendar.integration.test.js.map +1 -0
  5. package/dist/__tests__/forms.integration.test.d.ts +2 -0
  6. package/dist/__tests__/forms.integration.test.d.ts.map +1 -0
  7. package/dist/__tests__/forms.integration.test.js +243 -0
  8. package/dist/__tests__/forms.integration.test.js.map +1 -0
  9. package/dist/__tests__/gdrive.integration.test.d.ts +2 -0
  10. package/dist/__tests__/gdrive.integration.test.d.ts.map +1 -0
  11. package/dist/__tests__/gdrive.integration.test.js +186 -0
  12. package/dist/__tests__/gdrive.integration.test.js.map +1 -0
  13. package/dist/__tests__/gmail.integration.test.d.ts +2 -0
  14. package/dist/__tests__/gmail.integration.test.d.ts.map +1 -0
  15. package/dist/__tests__/gmail.integration.test.js +197 -0
  16. package/dist/__tests__/gmail.integration.test.js.map +1 -0
  17. package/dist/__tests__/gslides.integration.test.d.ts +2 -0
  18. package/dist/__tests__/gslides.integration.test.d.ts.map +1 -0
  19. package/dist/__tests__/gslides.integration.test.js +124 -0
  20. package/dist/__tests__/gslides.integration.test.js.map +1 -0
  21. package/dist/__tests__/sheets.integration.test.d.ts +2 -0
  22. package/dist/__tests__/sheets.integration.test.d.ts.map +1 -0
  23. package/dist/__tests__/sheets.integration.test.js +150 -0
  24. package/dist/__tests__/sheets.integration.test.js.map +1 -0
  25. package/dist/agent/crud.d.ts +6 -0
  26. package/dist/agent/crud.d.ts.map +1 -0
  27. package/dist/agent/crud.js +41 -0
  28. package/dist/agent/crud.js.map +1 -0
  29. package/dist/agent/memory.d.ts +14 -0
  30. package/dist/agent/memory.d.ts.map +1 -0
  31. package/dist/agent/memory.js +66 -0
  32. package/dist/agent/memory.js.map +1 -0
  33. package/dist/agent/permissions.d.ts +4 -0
  34. package/dist/agent/permissions.d.ts.map +1 -0
  35. package/dist/agent/permissions.js +32 -0
  36. package/dist/agent/permissions.js.map +1 -0
  37. package/dist/calendar/accounts.d.ts +3 -0
  38. package/dist/calendar/accounts.d.ts.map +1 -0
  39. package/dist/calendar/accounts.js +21 -0
  40. package/dist/calendar/accounts.js.map +1 -0
  41. package/dist/calendar/auth.d.ts +3 -0
  42. package/dist/calendar/auth.d.ts.map +1 -0
  43. package/dist/calendar/auth.js +41 -0
  44. package/dist/calendar/auth.js.map +1 -0
  45. package/dist/calendar/calendars.d.ts +3 -0
  46. package/dist/calendar/calendars.d.ts.map +1 -0
  47. package/dist/calendar/calendars.js +28 -0
  48. package/dist/calendar/calendars.js.map +1 -0
  49. package/dist/calendar/create.d.ts +3 -0
  50. package/dist/calendar/create.d.ts.map +1 -0
  51. package/dist/calendar/create.js +31 -0
  52. package/dist/calendar/create.js.map +1 -0
  53. package/dist/calendar/delete.d.ts +3 -0
  54. package/dist/calendar/delete.d.ts.map +1 -0
  55. package/dist/calendar/delete.js +21 -0
  56. package/dist/calendar/delete.js.map +1 -0
  57. package/dist/calendar/events.d.ts +3 -0
  58. package/dist/calendar/events.d.ts.map +1 -0
  59. package/dist/calendar/events.js +37 -0
  60. package/dist/calendar/events.js.map +1 -0
  61. package/dist/calendar/get.d.ts +3 -0
  62. package/dist/calendar/get.d.ts.map +1 -0
  63. package/dist/calendar/get.js +21 -0
  64. package/dist/calendar/get.js.map +1 -0
  65. package/dist/calendar/update.d.ts +3 -0
  66. package/dist/calendar/update.d.ts.map +1 -0
  67. package/dist/calendar/update.js +31 -0
  68. package/dist/calendar/update.js.map +1 -0
  69. package/dist/cli.d.ts +3 -0
  70. package/dist/cli.d.ts.map +1 -0
  71. package/dist/cli.js +37 -0
  72. package/dist/cli.js.map +1 -0
  73. package/dist/commands/agent.d.ts +6 -0
  74. package/dist/commands/agent.d.ts.map +1 -0
  75. package/dist/commands/agent.js +107 -0
  76. package/dist/commands/agent.js.map +1 -0
  77. package/dist/commands/calendar.d.ts +9 -0
  78. package/dist/commands/calendar.d.ts.map +1 -0
  79. package/dist/commands/calendar.js +104 -0
  80. package/dist/commands/calendar.js.map +1 -0
  81. package/dist/commands/cron.d.ts +6 -0
  82. package/dist/commands/cron.d.ts.map +1 -0
  83. package/dist/commands/cron.js +103 -0
  84. package/dist/commands/cron.js.map +1 -0
  85. package/dist/commands/forms.d.ts +9 -0
  86. package/dist/commands/forms.d.ts.map +1 -0
  87. package/dist/commands/forms.js +139 -0
  88. package/dist/commands/forms.js.map +1 -0
  89. package/dist/commands/gdrive.d.ts +9 -0
  90. package/dist/commands/gdrive.d.ts.map +1 -0
  91. package/dist/commands/gdrive.js +198 -0
  92. package/dist/commands/gdrive.js.map +1 -0
  93. package/dist/commands/gmail.d.ts +9 -0
  94. package/dist/commands/gmail.d.ts.map +1 -0
  95. package/dist/commands/gmail.js +231 -0
  96. package/dist/commands/gmail.js.map +1 -0
  97. package/dist/commands/gslides.d.ts +9 -0
  98. package/dist/commands/gslides.d.ts.map +1 -0
  99. package/dist/commands/gslides.js +167 -0
  100. package/dist/commands/gslides.js.map +1 -0
  101. package/dist/commands/sheets.d.ts +9 -0
  102. package/dist/commands/sheets.d.ts.map +1 -0
  103. package/dist/commands/sheets.js +174 -0
  104. package/dist/commands/sheets.js.map +1 -0
  105. package/dist/cron/daemon.d.ts +3 -0
  106. package/dist/cron/daemon.d.ts.map +1 -0
  107. package/dist/cron/daemon.js +127 -0
  108. package/dist/cron/daemon.js.map +1 -0
  109. package/dist/cron/handlers.d.ts +6 -0
  110. package/dist/cron/handlers.d.ts.map +1 -0
  111. package/dist/cron/handlers.js +58 -0
  112. package/dist/cron/handlers.js.map +1 -0
  113. package/dist/cron/logger.d.ts +4 -0
  114. package/dist/cron/logger.d.ts.map +1 -0
  115. package/dist/cron/logger.js +11 -0
  116. package/dist/cron/logger.js.map +1 -0
  117. package/dist/cron/progress.d.ts +25 -0
  118. package/dist/cron/progress.d.ts.map +1 -0
  119. package/dist/cron/progress.js +71 -0
  120. package/dist/cron/progress.js.map +1 -0
  121. package/dist/cron/ralph-wiggum.d.ts +18 -0
  122. package/dist/cron/ralph-wiggum.d.ts.map +1 -0
  123. package/dist/cron/ralph-wiggum.js +143 -0
  124. package/dist/cron/ralph-wiggum.js.map +1 -0
  125. package/dist/forms/accounts.d.ts +3 -0
  126. package/dist/forms/accounts.d.ts.map +1 -0
  127. package/dist/forms/accounts.js +20 -0
  128. package/dist/forms/accounts.js.map +1 -0
  129. package/dist/forms/auth.d.ts +3 -0
  130. package/dist/forms/auth.d.ts.map +1 -0
  131. package/dist/forms/auth.js +41 -0
  132. package/dist/forms/auth.js.map +1 -0
  133. package/dist/forms/create.d.ts +3 -0
  134. package/dist/forms/create.d.ts.map +1 -0
  135. package/dist/forms/create.js +28 -0
  136. package/dist/forms/create.js.map +1 -0
  137. package/dist/forms/get.d.ts +3 -0
  138. package/dist/forms/get.d.ts.map +1 -0
  139. package/dist/forms/get.js +21 -0
  140. package/dist/forms/get.js.map +1 -0
  141. package/dist/forms/list.d.ts +3 -0
  142. package/dist/forms/list.d.ts.map +1 -0
  143. package/dist/forms/list.js +33 -0
  144. package/dist/forms/list.js.map +1 -0
  145. package/dist/forms/questions.d.ts +6 -0
  146. package/dist/forms/questions.d.ts.map +1 -0
  147. package/dist/forms/questions.js +179 -0
  148. package/dist/forms/questions.js.map +1 -0
  149. package/dist/forms/responses.d.ts +4 -0
  150. package/dist/forms/responses.d.ts.map +1 -0
  151. package/dist/forms/responses.js +40 -0
  152. package/dist/forms/responses.js.map +1 -0
  153. package/dist/forms/update.d.ts +3 -0
  154. package/dist/forms/update.d.ts.map +1 -0
  155. package/dist/forms/update.js +44 -0
  156. package/dist/forms/update.js.map +1 -0
  157. package/dist/gdrive/about.d.ts +3 -0
  158. package/dist/gdrive/about.d.ts.map +1 -0
  159. package/dist/gdrive/about.js +31 -0
  160. package/dist/gdrive/about.js.map +1 -0
  161. package/dist/gdrive/accounts.d.ts +3 -0
  162. package/dist/gdrive/accounts.d.ts.map +1 -0
  163. package/dist/gdrive/accounts.js +20 -0
  164. package/dist/gdrive/accounts.js.map +1 -0
  165. package/dist/gdrive/auth.d.ts +3 -0
  166. package/dist/gdrive/auth.d.ts.map +1 -0
  167. package/dist/gdrive/auth.js +51 -0
  168. package/dist/gdrive/auth.js.map +1 -0
  169. package/dist/gdrive/files.d.ts +12 -0
  170. package/dist/gdrive/files.d.ts.map +1 -0
  171. package/dist/gdrive/files.js +174 -0
  172. package/dist/gdrive/files.js.map +1 -0
  173. package/dist/gdrive/folders.d.ts +4 -0
  174. package/dist/gdrive/folders.d.ts.map +1 -0
  175. package/dist/gdrive/folders.js +46 -0
  176. package/dist/gdrive/folders.js.map +1 -0
  177. package/dist/gdrive/search.d.ts +3 -0
  178. package/dist/gdrive/search.d.ts.map +1 -0
  179. package/dist/gdrive/search.js +23 -0
  180. package/dist/gdrive/search.js.map +1 -0
  181. package/dist/gdrive/sharing.d.ts +5 -0
  182. package/dist/gdrive/sharing.d.ts.map +1 -0
  183. package/dist/gdrive/sharing.js +54 -0
  184. package/dist/gdrive/sharing.js.map +1 -0
  185. package/dist/gmail/accounts.d.ts +3 -0
  186. package/dist/gmail/accounts.d.ts.map +1 -0
  187. package/dist/gmail/accounts.js +18 -0
  188. package/dist/gmail/accounts.js.map +1 -0
  189. package/dist/gmail/auth.d.ts +3 -0
  190. package/dist/gmail/auth.d.ts.map +1 -0
  191. package/dist/gmail/auth.js +50 -0
  192. package/dist/gmail/auth.js.map +1 -0
  193. package/dist/gmail/drafts.d.ts +7 -0
  194. package/dist/gmail/drafts.d.ts.map +1 -0
  195. package/dist/gmail/drafts.js +103 -0
  196. package/dist/gmail/drafts.js.map +1 -0
  197. package/dist/gmail/get.d.ts +4 -0
  198. package/dist/gmail/get.d.ts.map +1 -0
  199. package/dist/gmail/get.js +140 -0
  200. package/dist/gmail/get.js.map +1 -0
  201. package/dist/gmail/inbox.d.ts +4 -0
  202. package/dist/gmail/inbox.d.ts.map +1 -0
  203. package/dist/gmail/inbox.js +45 -0
  204. package/dist/gmail/inbox.js.map +1 -0
  205. package/dist/gmail/labels.d.ts +5 -0
  206. package/dist/gmail/labels.d.ts.map +1 -0
  207. package/dist/gmail/labels.js +45 -0
  208. package/dist/gmail/labels.js.map +1 -0
  209. package/dist/gmail/modify.d.ts +5 -0
  210. package/dist/gmail/modify.d.ts.map +1 -0
  211. package/dist/gmail/modify.js +68 -0
  212. package/dist/gmail/modify.js.map +1 -0
  213. package/dist/gmail/send.d.ts +5 -0
  214. package/dist/gmail/send.d.ts.map +1 -0
  215. package/dist/gmail/send.js +310 -0
  216. package/dist/gmail/send.js.map +1 -0
  217. package/dist/gmail/threads.d.ts +4 -0
  218. package/dist/gmail/threads.d.ts.map +1 -0
  219. package/dist/gmail/threads.js +47 -0
  220. package/dist/gmail/threads.js.map +1 -0
  221. package/dist/gslides/accounts.d.ts +3 -0
  222. package/dist/gslides/accounts.d.ts.map +1 -0
  223. package/dist/gslides/accounts.js +20 -0
  224. package/dist/gslides/accounts.js.map +1 -0
  225. package/dist/gslides/auth.d.ts +3 -0
  226. package/dist/gslides/auth.d.ts.map +1 -0
  227. package/dist/gslides/auth.js +50 -0
  228. package/dist/gslides/auth.js.map +1 -0
  229. package/dist/gslides/presentations.d.ts +29 -0
  230. package/dist/gslides/presentations.d.ts.map +1 -0
  231. package/dist/gslides/presentations.js +320 -0
  232. package/dist/gslides/presentations.js.map +1 -0
  233. package/dist/lib/config.d.ts +6 -0
  234. package/dist/lib/config.d.ts.map +1 -0
  235. package/dist/lib/config.js +12 -0
  236. package/dist/lib/config.js.map +1 -0
  237. package/dist/lib/media-utils.d.ts +5 -0
  238. package/dist/lib/media-utils.d.ts.map +1 -0
  239. package/dist/lib/media-utils.js +79 -0
  240. package/dist/lib/media-utils.js.map +1 -0
  241. package/dist/lib/output.d.ts +4 -0
  242. package/dist/lib/output.d.ts.map +1 -0
  243. package/dist/lib/output.js +12 -0
  244. package/dist/lib/output.js.map +1 -0
  245. package/dist/sheets/accounts.d.ts +3 -0
  246. package/dist/sheets/accounts.d.ts.map +1 -0
  247. package/dist/sheets/accounts.js +20 -0
  248. package/dist/sheets/accounts.js.map +1 -0
  249. package/dist/sheets/auth.d.ts +3 -0
  250. package/dist/sheets/auth.d.ts.map +1 -0
  251. package/dist/sheets/auth.js +56 -0
  252. package/dist/sheets/auth.js.map +1 -0
  253. package/dist/sheets/cells.d.ts +6 -0
  254. package/dist/sheets/cells.d.ts.map +1 -0
  255. package/dist/sheets/cells.js +89 -0
  256. package/dist/sheets/cells.js.map +1 -0
  257. package/dist/sheets/format.d.ts +8 -0
  258. package/dist/sheets/format.d.ts.map +1 -0
  259. package/dist/sheets/format.js +97 -0
  260. package/dist/sheets/format.js.map +1 -0
  261. package/dist/sheets/sheets-tab.d.ts +6 -0
  262. package/dist/sheets/sheets-tab.d.ts.map +1 -0
  263. package/dist/sheets/sheets-tab.js +88 -0
  264. package/dist/sheets/sheets-tab.js.map +1 -0
  265. package/dist/sheets/spreadsheets.d.ts +6 -0
  266. package/dist/sheets/spreadsheets.d.ts.map +1 -0
  267. package/dist/sheets/spreadsheets.js +88 -0
  268. package/dist/sheets/spreadsheets.js.map +1 -0
  269. package/package.json +33 -0
  270. package/src/__tests__/calendar.integration.test.ts +152 -0
  271. package/src/__tests__/forms.integration.test.ts +403 -0
  272. package/src/__tests__/gdrive.integration.test.ts +253 -0
  273. package/src/__tests__/gmail.integration.test.ts +294 -0
  274. package/src/__tests__/gslides.integration.test.ts +195 -0
  275. package/src/__tests__/sheets.integration.test.ts +234 -0
  276. package/src/agent/crud.ts +54 -0
  277. package/src/agent/memory.ts +95 -0
  278. package/src/agent/permissions.ts +54 -0
  279. package/src/calendar/accounts.ts +25 -0
  280. package/src/calendar/auth.ts +45 -0
  281. package/src/calendar/calendars.ts +32 -0
  282. package/src/calendar/create.ts +44 -0
  283. package/src/calendar/delete.ts +27 -0
  284. package/src/calendar/events.ts +45 -0
  285. package/src/calendar/get.ts +27 -0
  286. package/src/calendar/update.ts +44 -0
  287. package/src/cli.ts +41 -0
  288. package/src/commands/agent.ts +128 -0
  289. package/src/commands/calendar.ts +127 -0
  290. package/src/commands/cron.ts +126 -0
  291. package/src/commands/forms.ts +158 -0
  292. package/src/commands/gdrive.ts +225 -0
  293. package/src/commands/gmail.ts +290 -0
  294. package/src/commands/gslides.ts +188 -0
  295. package/src/commands/sheets.ts +193 -0
  296. package/src/cron/daemon.ts +143 -0
  297. package/src/cron/handlers.ts +78 -0
  298. package/src/cron/logger.ts +20 -0
  299. package/src/cron/progress.ts +90 -0
  300. package/src/cron/ralph-wiggum.ts +172 -0
  301. package/src/forms/accounts.ts +24 -0
  302. package/src/forms/auth.ts +45 -0
  303. package/src/forms/create.ts +34 -0
  304. package/src/forms/get.ts +26 -0
  305. package/src/forms/list.ts +38 -0
  306. package/src/forms/questions.ts +209 -0
  307. package/src/forms/responses.ts +50 -0
  308. package/src/forms/update.ts +57 -0
  309. package/src/gdrive/about.ts +36 -0
  310. package/src/gdrive/accounts.ts +24 -0
  311. package/src/gdrive/auth.ts +55 -0
  312. package/src/gdrive/files.ts +237 -0
  313. package/src/gdrive/folders.ts +58 -0
  314. package/src/gdrive/search.ts +30 -0
  315. package/src/gdrive/sharing.ts +72 -0
  316. package/src/gmail/accounts.ts +22 -0
  317. package/src/gmail/auth.ts +53 -0
  318. package/src/gmail/drafts.ts +166 -0
  319. package/src/gmail/get.ts +195 -0
  320. package/src/gmail/inbox.ts +78 -0
  321. package/src/gmail/labels.ts +69 -0
  322. package/src/gmail/modify.ts +89 -0
  323. package/src/gmail/send.ts +424 -0
  324. package/src/gmail/threads.ts +68 -0
  325. package/src/gslides/accounts.ts +24 -0
  326. package/src/gslides/auth.ts +54 -0
  327. package/src/gslides/presentations.ts +384 -0
  328. package/src/lib/config.ts +14 -0
  329. package/src/lib/media-utils.ts +82 -0
  330. package/src/lib/output.ts +13 -0
  331. package/src/sheets/accounts.ts +24 -0
  332. package/src/sheets/auth.ts +60 -0
  333. package/src/sheets/cells.ts +112 -0
  334. package/src/sheets/format.ts +114 -0
  335. package/src/sheets/sheets-tab.ts +109 -0
  336. package/src/sheets/spreadsheets.ts +106 -0
  337. package/tsconfig.json +8 -0
  338. package/vitest.config.ts +7 -0
@@ -0,0 +1,158 @@
1
+ import { Command } from "commander";
2
+ import type { OAuthClientManager } from "@digitalpresence/cliclaw-auth";
3
+ import { handleAuth } from "../forms/auth.js";
4
+ import { handleAccounts } from "../forms/accounts.js";
5
+ import { handleList } from "../forms/list.js";
6
+ import { handleGetForm } from "../forms/get.js";
7
+ import { handleCreateForm } from "../forms/create.js";
8
+ import { handleUpdateForm } from "../forms/update.js";
9
+ import { handleQuestions, handleAddQuestion, handleUpdateQuestion, handleDeleteQuestion } from "../forms/questions.js";
10
+ import { handleResponses, handleGetResponse } from "../forms/responses.js";
11
+
12
+ type ClientFactory = () => { clientManager: OAuthClientManager; port: number };
13
+
14
+ export function registerFormsCommands(program: Command, getClient: ClientFactory): void {
15
+ let cached: { clientManager: OAuthClientManager; port: number } | null = null;
16
+ function resolve() {
17
+ if (!cached) cached = getClient();
18
+ return cached;
19
+ }
20
+
21
+ const forms = program.command("forms").description("Google Forms commands");
22
+
23
+ forms
24
+ .command("auth")
25
+ .description("Authenticate with Google Forms via Google OAuth2")
26
+ .option("--account <name>", "Account name", "default")
27
+ .action(async (opts) => {
28
+ const { clientManager, port } = resolve();
29
+ await handleAuth(clientManager, port, opts.account);
30
+ });
31
+
32
+ forms
33
+ .command("accounts")
34
+ .description("List authenticated Google Forms accounts")
35
+ .action(async () => {
36
+ const { clientManager } = resolve();
37
+ await handleAccounts(clientManager);
38
+ });
39
+
40
+ forms
41
+ .command("list")
42
+ .description("List all forms")
43
+ .option("--max-results <n>", "Maximum forms to return", "20")
44
+ .option("--account <name>", "Account name", "default")
45
+ .action(async (opts) => {
46
+ const { clientManager } = resolve();
47
+ await handleList(clientManager, opts.account, parseInt(opts.maxResults));
48
+ });
49
+
50
+ forms
51
+ .command("get")
52
+ .description("Get form details by ID")
53
+ .requiredOption("--form-id <id>", "Form ID")
54
+ .option("--account <name>", "Account name", "default")
55
+ .action(async (opts) => {
56
+ const { clientManager } = resolve();
57
+ await handleGetForm(clientManager, opts.account, opts.formId);
58
+ });
59
+
60
+ forms
61
+ .command("create")
62
+ .description("Create a new form")
63
+ .requiredOption("--title <text>", "Form title")
64
+ .option("--document-title <text>", "Document title (defaults to form title)")
65
+ .option("--account <name>", "Account name", "default")
66
+ .action(async (opts) => {
67
+ const { clientManager } = resolve();
68
+ await handleCreateForm(clientManager, opts.account, opts.title, opts.documentTitle);
69
+ });
70
+
71
+ forms
72
+ .command("update")
73
+ .description("Update form metadata")
74
+ .requiredOption("--form-id <id>", "Form ID")
75
+ .option("--title <text>", "New form title")
76
+ .option("--description <text>", "New form description")
77
+ .option("--account <name>", "Account name", "default")
78
+ .action(async (opts) => {
79
+ const { clientManager } = resolve();
80
+ await handleUpdateForm(clientManager, opts.account, opts.formId, opts.title, opts.description);
81
+ });
82
+
83
+ forms
84
+ .command("questions")
85
+ .description("List questions in a form")
86
+ .requiredOption("--form-id <id>", "Form ID")
87
+ .option("--account <name>", "Account name", "default")
88
+ .action(async (opts) => {
89
+ const { clientManager } = resolve();
90
+ await handleQuestions(clientManager, opts.account, opts.formId);
91
+ });
92
+
93
+ forms
94
+ .command("add-question")
95
+ .description("Add a question to a form")
96
+ .requiredOption("--form-id <id>", "Form ID")
97
+ .requiredOption("--title <text>", "Question title")
98
+ .option("--type <type>", "Question type: text, paragraph, choice, checkbox, dropdown, scale, date, time", "text")
99
+ .option("--required", "Make question required", false)
100
+ .option("--options <items>", "Comma-separated options (for choice, checkbox, dropdown)")
101
+ .option("--index <n>", "Position index (0-based)")
102
+ .option("--account <name>", "Account name", "default")
103
+ .action(async (opts) => {
104
+ const { clientManager } = resolve();
105
+ const options = opts.options ? opts.options.split(",").map((o: string) => o.trim()) : undefined;
106
+ const index = opts.index !== undefined ? parseInt(opts.index) : undefined;
107
+ await handleAddQuestion(clientManager, opts.account, opts.formId, opts.title, opts.type, opts.required, options, index);
108
+ });
109
+
110
+ forms
111
+ .command("update-question")
112
+ .description("Update a question in a form")
113
+ .requiredOption("--form-id <id>", "Form ID")
114
+ .requiredOption("--item-index <n>", "Item index (0-based)")
115
+ .option("--title <text>", "New question title")
116
+ .option("--required", "Make question required")
117
+ .option("--no-required", "Make question optional")
118
+ .option("--account <name>", "Account name", "default")
119
+ .action(async (opts) => {
120
+ const { clientManager } = resolve();
121
+ await handleUpdateQuestion(
122
+ clientManager, opts.account, opts.formId,
123
+ parseInt(opts.itemIndex), opts.title, opts.required,
124
+ );
125
+ });
126
+
127
+ forms
128
+ .command("delete-question")
129
+ .description("Delete a question from a form")
130
+ .requiredOption("--form-id <id>", "Form ID")
131
+ .requiredOption("--item-index <n>", "Item index (0-based)")
132
+ .option("--account <name>", "Account name", "default")
133
+ .action(async (opts) => {
134
+ const { clientManager } = resolve();
135
+ await handleDeleteQuestion(clientManager, opts.account, opts.formId, parseInt(opts.itemIndex));
136
+ });
137
+
138
+ forms
139
+ .command("responses")
140
+ .description("List all responses for a form")
141
+ .requiredOption("--form-id <id>", "Form ID")
142
+ .option("--account <name>", "Account name", "default")
143
+ .action(async (opts) => {
144
+ const { clientManager } = resolve();
145
+ await handleResponses(clientManager, opts.account, opts.formId);
146
+ });
147
+
148
+ forms
149
+ .command("response")
150
+ .description("Get a single response by ID")
151
+ .requiredOption("--form-id <id>", "Form ID")
152
+ .requiredOption("--response-id <id>", "Response ID")
153
+ .option("--account <name>", "Account name", "default")
154
+ .action(async (opts) => {
155
+ const { clientManager } = resolve();
156
+ await handleGetResponse(clientManager, opts.account, opts.formId, opts.responseId);
157
+ });
158
+ }
@@ -0,0 +1,225 @@
1
+ import { Command } from "commander";
2
+ import type { OAuthClientManager } from "@digitalpresence/cliclaw-auth";
3
+ import { handleAuth } from "../gdrive/auth.js";
4
+ import { handleAccounts } from "../gdrive/accounts.js";
5
+ import {
6
+ handleList, handleGet, handleDownload, handleUpload,
7
+ handleDelete, handleTrash, handleUntrash,
8
+ handleMove, handleCopy, handleRename,
9
+ } from "../gdrive/files.js";
10
+ import { handleMkdir, handleListFolder } from "../gdrive/folders.js";
11
+ import { handleSearch } from "../gdrive/search.js";
12
+ import { handleShare, handleUnshare, handlePermissions } from "../gdrive/sharing.js";
13
+ import { handleAbout } from "../gdrive/about.js";
14
+
15
+ type ClientFactory = () => { clientManager: OAuthClientManager; port: number };
16
+
17
+ export function registerGDriveCommands(program: Command, getClient: ClientFactory): void {
18
+ let cached: { clientManager: OAuthClientManager; port: number } | null = null;
19
+ function resolve() {
20
+ if (!cached) cached = getClient();
21
+ return cached;
22
+ }
23
+
24
+ const gdrive = program.command("gdrive").description("Google Drive commands");
25
+
26
+ gdrive
27
+ .command("auth")
28
+ .description("Authenticate with Google Drive via Google OAuth2")
29
+ .option("--account <name>", "Account name", "default")
30
+ .action(async (opts) => {
31
+ const { clientManager, port } = resolve();
32
+ await handleAuth(clientManager, port, opts.account);
33
+ });
34
+
35
+ gdrive
36
+ .command("accounts")
37
+ .description("List authenticated Google Drive accounts")
38
+ .action(async () => {
39
+ const { clientManager } = resolve();
40
+ await handleAccounts(clientManager);
41
+ });
42
+
43
+ gdrive
44
+ .command("list")
45
+ .description("List files in Google Drive")
46
+ .option("--max-results <n>", "Maximum files to return", "20")
47
+ .option("--query <query>", "Drive query filter (e.g. mimeType='application/pdf')")
48
+ .option("--account <name>", "Account name", "default")
49
+ .action(async (opts) => {
50
+ const { clientManager } = resolve();
51
+ await handleList(clientManager, opts.account, parseInt(opts.maxResults), opts.query);
52
+ });
53
+
54
+ gdrive
55
+ .command("get")
56
+ .description("Get file metadata by ID")
57
+ .requiredOption("--id <id>", "File ID")
58
+ .option("--account <name>", "Account name", "default")
59
+ .action(async (opts) => {
60
+ const { clientManager } = resolve();
61
+ await handleGet(clientManager, opts.account, opts.id);
62
+ });
63
+
64
+ gdrive
65
+ .command("download")
66
+ .description("Download a file")
67
+ .requiredOption("--id <id>", "File ID")
68
+ .requiredOption("--save-dir <dir>", "Directory to save to")
69
+ .option("--filename <name>", "Override filename")
70
+ .option("--account <name>", "Account name", "default")
71
+ .action(async (opts) => {
72
+ const { clientManager } = resolve();
73
+ await handleDownload(clientManager, opts.account, opts.id, opts.saveDir, opts.filename);
74
+ });
75
+
76
+ gdrive
77
+ .command("upload")
78
+ .description("Upload a file")
79
+ .requiredOption("--file <path>", "Local file path")
80
+ .option("--name <name>", "Override filename in Drive")
81
+ .option("--parent <id>", "Parent folder ID")
82
+ .option("--account <name>", "Account name", "default")
83
+ .action(async (opts) => {
84
+ const { clientManager } = resolve();
85
+ await handleUpload(clientManager, opts.account, opts.file, opts.name, opts.parent);
86
+ });
87
+
88
+ gdrive
89
+ .command("delete")
90
+ .description("Permanently delete a file")
91
+ .requiredOption("--id <id>", "File ID")
92
+ .option("--account <name>", "Account name", "default")
93
+ .action(async (opts) => {
94
+ const { clientManager } = resolve();
95
+ await handleDelete(clientManager, opts.account, opts.id);
96
+ });
97
+
98
+ gdrive
99
+ .command("trash")
100
+ .description("Move a file to trash")
101
+ .requiredOption("--id <id>", "File ID")
102
+ .option("--account <name>", "Account name", "default")
103
+ .action(async (opts) => {
104
+ const { clientManager } = resolve();
105
+ await handleTrash(clientManager, opts.account, opts.id);
106
+ });
107
+
108
+ gdrive
109
+ .command("untrash")
110
+ .description("Restore a file from trash")
111
+ .requiredOption("--id <id>", "File ID")
112
+ .option("--account <name>", "Account name", "default")
113
+ .action(async (opts) => {
114
+ const { clientManager } = resolve();
115
+ await handleUntrash(clientManager, opts.account, opts.id);
116
+ });
117
+
118
+ gdrive
119
+ .command("move")
120
+ .description("Move a file to a different folder")
121
+ .requiredOption("--id <id>", "File ID")
122
+ .requiredOption("--to <folder-id>", "Destination folder ID")
123
+ .option("--account <name>", "Account name", "default")
124
+ .action(async (opts) => {
125
+ const { clientManager } = resolve();
126
+ await handleMove(clientManager, opts.account, opts.id, opts.to);
127
+ });
128
+
129
+ gdrive
130
+ .command("copy")
131
+ .description("Copy a file")
132
+ .requiredOption("--id <id>", "File ID")
133
+ .option("--name <name>", "Name for the copy")
134
+ .option("--account <name>", "Account name", "default")
135
+ .action(async (opts) => {
136
+ const { clientManager } = resolve();
137
+ await handleCopy(clientManager, opts.account, opts.id, opts.name);
138
+ });
139
+
140
+ gdrive
141
+ .command("rename")
142
+ .description("Rename a file")
143
+ .requiredOption("--id <id>", "File ID")
144
+ .requiredOption("--name <name>", "New name")
145
+ .option("--account <name>", "Account name", "default")
146
+ .action(async (opts) => {
147
+ const { clientManager } = resolve();
148
+ await handleRename(clientManager, opts.account, opts.id, opts.name);
149
+ });
150
+
151
+ gdrive
152
+ .command("mkdir")
153
+ .description("Create a new folder")
154
+ .requiredOption("--name <name>", "Folder name")
155
+ .option("--parent <id>", "Parent folder ID")
156
+ .option("--account <name>", "Account name", "default")
157
+ .action(async (opts) => {
158
+ const { clientManager } = resolve();
159
+ await handleMkdir(clientManager, opts.account, opts.name, opts.parent);
160
+ });
161
+
162
+ gdrive
163
+ .command("list-folder")
164
+ .description("List contents of a specific folder")
165
+ .requiredOption("--id <id>", "Folder ID")
166
+ .option("--max-results <n>", "Maximum items to return", "50")
167
+ .option("--account <name>", "Account name", "default")
168
+ .action(async (opts) => {
169
+ const { clientManager } = resolve();
170
+ await handleListFolder(clientManager, opts.account, opts.id, parseInt(opts.maxResults));
171
+ });
172
+
173
+ gdrive
174
+ .command("search")
175
+ .description("Full-text search across Drive")
176
+ .requiredOption("--query <query>", "Search query")
177
+ .option("--max-results <n>", "Maximum results to return", "20")
178
+ .option("--account <name>", "Account name", "default")
179
+ .action(async (opts) => {
180
+ const { clientManager } = resolve();
181
+ await handleSearch(clientManager, opts.account, opts.query, parseInt(opts.maxResults));
182
+ });
183
+
184
+ gdrive
185
+ .command("share")
186
+ .description("Share a file with a user")
187
+ .requiredOption("--id <id>", "File ID")
188
+ .requiredOption("--email <email>", "Email to share with")
189
+ .option("--role <role>", "Permission role: reader, writer, commenter", "reader")
190
+ .option("--account <name>", "Account name", "default")
191
+ .action(async (opts) => {
192
+ const { clientManager } = resolve();
193
+ await handleShare(clientManager, opts.account, opts.id, opts.email, opts.role);
194
+ });
195
+
196
+ gdrive
197
+ .command("unshare")
198
+ .description("Remove a permission from a file")
199
+ .requiredOption("--id <id>", "File ID")
200
+ .requiredOption("--permission-id <pid>", "Permission ID to remove")
201
+ .option("--account <name>", "Account name", "default")
202
+ .action(async (opts) => {
203
+ const { clientManager } = resolve();
204
+ await handleUnshare(clientManager, opts.account, opts.id, opts.permissionId);
205
+ });
206
+
207
+ gdrive
208
+ .command("permissions")
209
+ .description("List permissions on a file")
210
+ .requiredOption("--id <id>", "File ID")
211
+ .option("--account <name>", "Account name", "default")
212
+ .action(async (opts) => {
213
+ const { clientManager } = resolve();
214
+ await handlePermissions(clientManager, opts.account, opts.id);
215
+ });
216
+
217
+ gdrive
218
+ .command("about")
219
+ .description("Show storage quota and user info")
220
+ .option("--account <name>", "Account name", "default")
221
+ .action(async (opts) => {
222
+ const { clientManager } = resolve();
223
+ await handleAbout(clientManager, opts.account);
224
+ });
225
+ }
@@ -0,0 +1,290 @@
1
+ import { Command } from "commander";
2
+ import type { OAuthClientManager } from "@digitalpresence/cliclaw-auth";
3
+ import { handleAuth } from "../gmail/auth.js";
4
+ import { handleAccounts } from "../gmail/accounts.js";
5
+ import { handleInbox, handleSearch } from "../gmail/inbox.js";
6
+ import { handleGet, handleDownloadAttachment } from "../gmail/get.js";
7
+ import { handleSend, handleReply, handleForward } from "../gmail/send.js";
8
+ import { handleModify } from "../gmail/modify.js";
9
+ import { handleDraftList, handleDraftCreate, handleDraftUpdate, handleDraftDelete, handleDraftSend } from "../gmail/drafts.js";
10
+ import { handleLabelsList, handleLabelCreate, handleLabelDelete } from "../gmail/labels.js";
11
+ import { handleThreadList, handleThreadGet } from "../gmail/threads.js";
12
+
13
+ type ClientFactory = () => { clientManager: OAuthClientManager; port: number };
14
+
15
+ export function registerGmailCommands(program: Command, getClient: ClientFactory): void {
16
+ // Cache so we only call the factory once
17
+ let cached: { clientManager: OAuthClientManager; port: number } | null = null;
18
+ function resolve() {
19
+ if (!cached) cached = getClient();
20
+ return cached;
21
+ }
22
+
23
+ const gmail = program.command("gmail").description("Gmail commands");
24
+
25
+ gmail
26
+ .command("auth")
27
+ .description("Authenticate with Gmail via Google OAuth2")
28
+ .option("--account <name>", "Account name", "default")
29
+ .action(async (opts) => {
30
+ const { clientManager, port } = resolve();
31
+ await handleAuth(clientManager, port, opts.account);
32
+ });
33
+
34
+ gmail
35
+ .command("accounts")
36
+ .description("List authenticated Gmail accounts")
37
+ .action(async () => {
38
+ const { clientManager } = resolve();
39
+ await handleAccounts(clientManager);
40
+ });
41
+
42
+ gmail
43
+ .command("inbox")
44
+ .description("List recent inbox messages")
45
+ .option("--max-results <n>", "Maximum messages to return", "20")
46
+ .option("--account <name>", "Account name", "default")
47
+ .action(async (opts) => {
48
+ const { clientManager } = resolve();
49
+ await handleInbox(clientManager, opts.account, parseInt(opts.maxResults));
50
+ });
51
+
52
+ gmail
53
+ .command("search")
54
+ .description("Search Gmail messages")
55
+ .requiredOption("--query <query>", "Gmail search query")
56
+ .option("--max-results <n>", "Maximum messages to return", "20")
57
+ .option("--account <name>", "Account name", "default")
58
+ .action(async (opts) => {
59
+ const { clientManager } = resolve();
60
+ await handleSearch(clientManager, opts.account, opts.query, parseInt(opts.maxResults));
61
+ });
62
+
63
+ gmail
64
+ .command("get")
65
+ .description("Get full message by ID")
66
+ .requiredOption("--id <id>", "Gmail message ID")
67
+ .option("--account <name>", "Account name", "default")
68
+ .action(async (opts) => {
69
+ const { clientManager } = resolve();
70
+ await handleGet(clientManager, opts.account, opts.id);
71
+ });
72
+
73
+ gmail
74
+ .command("send")
75
+ .description("Send a new email")
76
+ .requiredOption("--to <address>", "Recipient email")
77
+ .requiredOption("--subject <subject>", "Email subject")
78
+ .requiredOption("--body <text>", "Plain-text body")
79
+ .option("--cc <addresses>", "CC recipients")
80
+ .option("--bcc <addresses>", "BCC recipients")
81
+ .option("--html-body <html>", "HTML body")
82
+ .option("--attachment <path>", "File attachment path (repeatable)", (val: string, prev: string[]) => prev.concat(val), [] as string[])
83
+ .option("--account <name>", "Account name", "default")
84
+ .action(async (opts) => {
85
+ const { clientManager } = resolve();
86
+ await handleSend(
87
+ clientManager,
88
+ opts.account,
89
+ opts.to,
90
+ opts.subject,
91
+ opts.body,
92
+ opts.cc,
93
+ opts.bcc,
94
+ opts.htmlBody,
95
+ opts.attachment.length > 0 ? opts.attachment : undefined,
96
+ );
97
+ });
98
+
99
+ gmail
100
+ .command("reply")
101
+ .description("Reply to an existing message")
102
+ .requiredOption("--id <id>", "Message ID to reply to")
103
+ .requiredOption("--body <text>", "Reply body")
104
+ .option("--reply-all", "Reply to all recipients")
105
+ .option("--html-body <html>", "HTML reply body")
106
+ .option("--attachment <path>", "File attachment path (repeatable)", (val: string, prev: string[]) => prev.concat(val), [] as string[])
107
+ .option("--account <name>", "Account name", "default")
108
+ .action(async (opts) => {
109
+ const { clientManager } = resolve();
110
+ await handleReply(
111
+ clientManager,
112
+ opts.account,
113
+ opts.id,
114
+ opts.body,
115
+ opts.replyAll,
116
+ opts.htmlBody,
117
+ opts.attachment.length > 0 ? opts.attachment : undefined,
118
+ );
119
+ });
120
+
121
+ gmail
122
+ .command("forward")
123
+ .description("Forward a message")
124
+ .requiredOption("--id <id>", "Message ID to forward")
125
+ .requiredOption("--to <address>", "Recipient to forward to")
126
+ .option("--body <text>", "Introductory note")
127
+ .option("--attachment <path>", "File attachment path (repeatable)", (val: string, prev: string[]) => prev.concat(val), [] as string[])
128
+ .option("--account <name>", "Account name", "default")
129
+ .action(async (opts) => {
130
+ const { clientManager } = resolve();
131
+ await handleForward(
132
+ clientManager,
133
+ opts.account,
134
+ opts.id,
135
+ opts.to,
136
+ opts.body,
137
+ opts.attachment.length > 0 ? opts.attachment : undefined,
138
+ );
139
+ });
140
+
141
+ gmail
142
+ .command("modify")
143
+ .description("Modify message state (read/unread/archive/trash/star/labels)")
144
+ .requiredOption("--id <id>", "Message ID")
145
+ .requiredOption("--action <action>", "Action: mark_read, mark_unread, archive, trash, untrash, star, unstar, add_labels, remove_labels")
146
+ .option("--label-ids <ids...>", "Label IDs for add_labels/remove_labels")
147
+ .option("--account <name>", "Account name", "default")
148
+ .action(async (opts) => {
149
+ const { clientManager } = resolve();
150
+ await handleModify(clientManager, opts.account, opts.id, opts.action, opts.labelIds);
151
+ });
152
+
153
+ gmail
154
+ .command("download-attachment")
155
+ .description("Download an email attachment")
156
+ .requiredOption("--id <id>", "Message ID")
157
+ .requiredOption("--attachment-id <aid>", "Attachment ID")
158
+ .requiredOption("--filename <name>", "Filename to save as")
159
+ .requiredOption("--save-dir <dir>", "Directory to save to")
160
+ .option("--account <name>", "Account name", "default")
161
+ .action(async (opts) => {
162
+ const { clientManager } = resolve();
163
+ await handleDownloadAttachment(
164
+ clientManager,
165
+ opts.account,
166
+ opts.id,
167
+ opts.attachmentId,
168
+ opts.filename,
169
+ opts.saveDir,
170
+ );
171
+ });
172
+
173
+ // Drafts subcommand group
174
+ const drafts = gmail.command("drafts").description("Draft management");
175
+
176
+ drafts
177
+ .command("list")
178
+ .description("List drafts")
179
+ .option("--max-results <n>", "Maximum drafts to return", "20")
180
+ .option("--account <name>", "Account name", "default")
181
+ .action(async (opts) => {
182
+ const { clientManager } = resolve();
183
+ await handleDraftList(clientManager, opts.account, parseInt(opts.maxResults));
184
+ });
185
+
186
+ drafts
187
+ .command("create")
188
+ .description("Create a new draft")
189
+ .requiredOption("--to <address>", "Recipient email")
190
+ .requiredOption("--subject <subject>", "Email subject")
191
+ .requiredOption("--body <text>", "Plain-text body")
192
+ .option("--cc <addresses>", "CC recipients")
193
+ .option("--bcc <addresses>", "BCC recipients")
194
+ .option("--account <name>", "Account name", "default")
195
+ .action(async (opts) => {
196
+ const { clientManager } = resolve();
197
+ await handleDraftCreate(clientManager, opts.account, opts.to, opts.subject, opts.body, opts.cc, opts.bcc);
198
+ });
199
+
200
+ drafts
201
+ .command("update")
202
+ .description("Update an existing draft")
203
+ .requiredOption("--draft-id <id>", "Draft ID")
204
+ .requiredOption("--to <address>", "Recipient email")
205
+ .requiredOption("--subject <subject>", "Email subject")
206
+ .requiredOption("--body <text>", "Plain-text body")
207
+ .option("--cc <addresses>", "CC recipients")
208
+ .option("--bcc <addresses>", "BCC recipients")
209
+ .option("--account <name>", "Account name", "default")
210
+ .action(async (opts) => {
211
+ const { clientManager } = resolve();
212
+ await handleDraftUpdate(clientManager, opts.account, opts.draftId, opts.to, opts.subject, opts.body, opts.cc, opts.bcc);
213
+ });
214
+
215
+ drafts
216
+ .command("delete")
217
+ .description("Delete a draft")
218
+ .requiredOption("--draft-id <id>", "Draft ID")
219
+ .option("--account <name>", "Account name", "default")
220
+ .action(async (opts) => {
221
+ const { clientManager } = resolve();
222
+ await handleDraftDelete(clientManager, opts.account, opts.draftId);
223
+ });
224
+
225
+ drafts
226
+ .command("send")
227
+ .description("Send a draft")
228
+ .requiredOption("--draft-id <id>", "Draft ID")
229
+ .option("--account <name>", "Account name", "default")
230
+ .action(async (opts) => {
231
+ const { clientManager } = resolve();
232
+ await handleDraftSend(clientManager, opts.account, opts.draftId);
233
+ });
234
+
235
+ // Labels subcommand group
236
+ const labels = gmail.command("labels").description("Label management");
237
+
238
+ labels
239
+ .command("list")
240
+ .description("List all labels")
241
+ .option("--account <name>", "Account name", "default")
242
+ .action(async (opts) => {
243
+ const { clientManager } = resolve();
244
+ await handleLabelsList(clientManager, opts.account);
245
+ });
246
+
247
+ labels
248
+ .command("create")
249
+ .description("Create a new label")
250
+ .requiredOption("--name <name>", "Label name")
251
+ .option("--account <name>", "Account name", "default")
252
+ .action(async (opts) => {
253
+ const { clientManager } = resolve();
254
+ await handleLabelCreate(clientManager, opts.account, opts.name);
255
+ });
256
+
257
+ labels
258
+ .command("delete")
259
+ .description("Delete a label")
260
+ .requiredOption("--label-id <id>", "Label ID")
261
+ .option("--account <name>", "Account name", "default")
262
+ .action(async (opts) => {
263
+ const { clientManager } = resolve();
264
+ await handleLabelDelete(clientManager, opts.account, opts.labelId);
265
+ });
266
+
267
+ // Threads subcommand group
268
+ const threads = gmail.command("threads").description("Thread management");
269
+
270
+ threads
271
+ .command("list")
272
+ .description("List threads")
273
+ .option("--query <query>", "Gmail search query")
274
+ .option("--max-results <n>", "Maximum threads to return", "20")
275
+ .option("--account <name>", "Account name", "default")
276
+ .action(async (opts) => {
277
+ const { clientManager } = resolve();
278
+ await handleThreadList(clientManager, opts.account, parseInt(opts.maxResults), opts.query);
279
+ });
280
+
281
+ threads
282
+ .command("get")
283
+ .description("Get all messages in a thread")
284
+ .requiredOption("--thread-id <id>", "Thread ID")
285
+ .option("--account <name>", "Account name", "default")
286
+ .action(async (opts) => {
287
+ const { clientManager } = resolve();
288
+ await handleThreadGet(clientManager, opts.account, opts.threadId);
289
+ });
290
+ }