sorokeep 1.0.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 (275) hide show
  1. package/CONTRIBUTING.md +296 -0
  2. package/LICENSE +21 -0
  3. package/README.md +677 -0
  4. package/dist/alerts/alerts.d.ts +21 -0
  5. package/dist/alerts/alerts.d.ts.map +1 -0
  6. package/dist/alerts/alerts.js +18 -0
  7. package/dist/alerts/alerts.js.map +1 -0
  8. package/dist/alerts/discord.d.ts +3 -0
  9. package/dist/alerts/discord.d.ts.map +1 -0
  10. package/dist/alerts/discord.js +199 -0
  11. package/dist/alerts/discord.js.map +1 -0
  12. package/dist/alerts/dispatcher.d.ts +13 -0
  13. package/dist/alerts/dispatcher.d.ts.map +1 -0
  14. package/dist/alerts/dispatcher.js +91 -0
  15. package/dist/alerts/dispatcher.js.map +1 -0
  16. package/dist/alerts/keys.d.ts +24 -0
  17. package/dist/alerts/keys.d.ts.map +1 -0
  18. package/dist/alerts/keys.js +44 -0
  19. package/dist/alerts/keys.js.map +1 -0
  20. package/dist/alerts/pagerduty.d.ts +8 -0
  21. package/dist/alerts/pagerduty.d.ts.map +1 -0
  22. package/dist/alerts/pagerduty.js +164 -0
  23. package/dist/alerts/pagerduty.js.map +1 -0
  24. package/dist/alerts/resource.d.ts +23 -0
  25. package/dist/alerts/resource.d.ts.map +1 -0
  26. package/dist/alerts/resource.js +167 -0
  27. package/dist/alerts/resource.js.map +1 -0
  28. package/dist/alerts/slack.d.ts +7 -0
  29. package/dist/alerts/slack.d.ts.map +1 -0
  30. package/dist/alerts/slack.js +184 -0
  31. package/dist/alerts/slack.js.map +1 -0
  32. package/dist/alerts/telegram.d.ts +9 -0
  33. package/dist/alerts/telegram.d.ts.map +1 -0
  34. package/dist/alerts/telegram.js +133 -0
  35. package/dist/alerts/telegram.js.map +1 -0
  36. package/dist/alerts/templates.d.ts +109 -0
  37. package/dist/alerts/templates.d.ts.map +1 -0
  38. package/dist/alerts/templates.js +139 -0
  39. package/dist/alerts/templates.js.map +1 -0
  40. package/dist/alerts/types.d.ts +113 -0
  41. package/dist/alerts/types.d.ts.map +1 -0
  42. package/dist/alerts/types.js +87 -0
  43. package/dist/alerts/types.js.map +1 -0
  44. package/dist/alerts/webhook.d.ts +13 -0
  45. package/dist/alerts/webhook.d.ts.map +1 -0
  46. package/dist/alerts/webhook.js +56 -0
  47. package/dist/alerts/webhook.js.map +1 -0
  48. package/dist/cli/schemaFormatter.d.ts +11 -0
  49. package/dist/cli/schemaFormatter.d.ts.map +1 -0
  50. package/dist/cli/schemaFormatter.js +74 -0
  51. package/dist/cli/schemaFormatter.js.map +1 -0
  52. package/dist/commands/alerts.d.ts +3 -0
  53. package/dist/commands/alerts.d.ts.map +1 -0
  54. package/dist/commands/alerts.js +256 -0
  55. package/dist/commands/alerts.js.map +1 -0
  56. package/dist/commands/budget.d.ts +3 -0
  57. package/dist/commands/budget.d.ts.map +1 -0
  58. package/dist/commands/budget.js +47 -0
  59. package/dist/commands/budget.js.map +1 -0
  60. package/dist/commands/channels.d.ts +3 -0
  61. package/dist/commands/channels.d.ts.map +1 -0
  62. package/dist/commands/channels.js +84 -0
  63. package/dist/commands/channels.js.map +1 -0
  64. package/dist/commands/check.d.ts +3 -0
  65. package/dist/commands/check.d.ts.map +1 -0
  66. package/dist/commands/check.js +58 -0
  67. package/dist/commands/check.js.map +1 -0
  68. package/dist/commands/completion.d.ts +3 -0
  69. package/dist/commands/completion.d.ts.map +1 -0
  70. package/dist/commands/completion.js +36 -0
  71. package/dist/commands/completion.js.map +1 -0
  72. package/dist/commands/costs.d.ts +15 -0
  73. package/dist/commands/costs.d.ts.map +1 -0
  74. package/dist/commands/costs.js +280 -0
  75. package/dist/commands/costs.js.map +1 -0
  76. package/dist/commands/daemon.d.ts +3 -0
  77. package/dist/commands/daemon.d.ts.map +1 -0
  78. package/dist/commands/daemon.js +93 -0
  79. package/dist/commands/daemon.js.map +1 -0
  80. package/dist/commands/db.d.ts +3 -0
  81. package/dist/commands/db.d.ts.map +1 -0
  82. package/dist/commands/db.js +140 -0
  83. package/dist/commands/db.js.map +1 -0
  84. package/dist/commands/guard.d.ts +3 -0
  85. package/dist/commands/guard.d.ts.map +1 -0
  86. package/dist/commands/guard.js +181 -0
  87. package/dist/commands/guard.js.map +1 -0
  88. package/dist/commands/history.d.ts +3 -0
  89. package/dist/commands/history.d.ts.map +1 -0
  90. package/dist/commands/history.js +57 -0
  91. package/dist/commands/history.js.map +1 -0
  92. package/dist/commands/inspect.d.ts +3 -0
  93. package/dist/commands/inspect.d.ts.map +1 -0
  94. package/dist/commands/inspect.js +82 -0
  95. package/dist/commands/inspect.js.map +1 -0
  96. package/dist/commands/mcp.d.ts +3 -0
  97. package/dist/commands/mcp.d.ts.map +1 -0
  98. package/dist/commands/mcp.js +20 -0
  99. package/dist/commands/mcp.js.map +1 -0
  100. package/dist/commands/pause.d.ts +3 -0
  101. package/dist/commands/pause.d.ts.map +1 -0
  102. package/dist/commands/pause.js +32 -0
  103. package/dist/commands/pause.js.map +1 -0
  104. package/dist/commands/resources.d.ts +3 -0
  105. package/dist/commands/resources.d.ts.map +1 -0
  106. package/dist/commands/resources.js +95 -0
  107. package/dist/commands/resources.js.map +1 -0
  108. package/dist/commands/restore.d.ts +3 -0
  109. package/dist/commands/restore.d.ts.map +1 -0
  110. package/dist/commands/restore.js +92 -0
  111. package/dist/commands/restore.js.map +1 -0
  112. package/dist/commands/resume.d.ts +3 -0
  113. package/dist/commands/resume.d.ts.map +1 -0
  114. package/dist/commands/resume.js +31 -0
  115. package/dist/commands/resume.js.map +1 -0
  116. package/dist/commands/status.d.ts +3 -0
  117. package/dist/commands/status.d.ts.map +1 -0
  118. package/dist/commands/status.js +63 -0
  119. package/dist/commands/status.js.map +1 -0
  120. package/dist/commands/watch.d.ts +3 -0
  121. package/dist/commands/watch.d.ts.map +1 -0
  122. package/dist/commands/watch.js +163 -0
  123. package/dist/commands/watch.js.map +1 -0
  124. package/dist/core/aws_secrets.d.ts +13 -0
  125. package/dist/core/aws_secrets.d.ts.map +1 -0
  126. package/dist/core/aws_secrets.js +34 -0
  127. package/dist/core/aws_secrets.js.map +1 -0
  128. package/dist/core/budget.d.ts +10 -0
  129. package/dist/core/budget.d.ts.map +1 -0
  130. package/dist/core/budget.js +31 -0
  131. package/dist/core/budget.js.map +1 -0
  132. package/dist/core/channels.d.ts +67 -0
  133. package/dist/core/channels.d.ts.map +1 -0
  134. package/dist/core/channels.js +136 -0
  135. package/dist/core/channels.js.map +1 -0
  136. package/dist/core/check.d.ts +25 -0
  137. package/dist/core/check.d.ts.map +1 -0
  138. package/dist/core/check.js +85 -0
  139. package/dist/core/check.js.map +1 -0
  140. package/dist/core/completion.d.ts +9 -0
  141. package/dist/core/completion.d.ts.map +1 -0
  142. package/dist/core/completion.js +68 -0
  143. package/dist/core/completion.js.map +1 -0
  144. package/dist/core/costs.d.ts +90 -0
  145. package/dist/core/costs.d.ts.map +1 -0
  146. package/dist/core/costs.js +147 -0
  147. package/dist/core/costs.js.map +1 -0
  148. package/dist/core/decoder.d.ts +7 -0
  149. package/dist/core/decoder.d.ts.map +1 -0
  150. package/dist/core/decoder.js +38 -0
  151. package/dist/core/decoder.js.map +1 -0
  152. package/dist/core/discovery.d.ts +38 -0
  153. package/dist/core/discovery.d.ts.map +1 -0
  154. package/dist/core/discovery.js +208 -0
  155. package/dist/core/discovery.js.map +1 -0
  156. package/dist/core/extension.d.ts +83 -0
  157. package/dist/core/extension.d.ts.map +1 -0
  158. package/dist/core/extension.js +429 -0
  159. package/dist/core/extension.js.map +1 -0
  160. package/dist/core/inspect.d.ts +62 -0
  161. package/dist/core/inspect.d.ts.map +1 -0
  162. package/dist/core/inspect.js +303 -0
  163. package/dist/core/inspect.js.map +1 -0
  164. package/dist/core/introspection.d.ts +8 -0
  165. package/dist/core/introspection.d.ts.map +1 -0
  166. package/dist/core/introspection.js +8 -0
  167. package/dist/core/introspection.js.map +1 -0
  168. package/dist/core/monitor.d.ts +42 -0
  169. package/dist/core/monitor.d.ts.map +1 -0
  170. package/dist/core/monitor.js +188 -0
  171. package/dist/core/monitor.js.map +1 -0
  172. package/dist/core/rent_projection.d.ts +153 -0
  173. package/dist/core/rent_projection.d.ts.map +1 -0
  174. package/dist/core/rent_projection.js +146 -0
  175. package/dist/core/rent_projection.js.map +1 -0
  176. package/dist/core/scvalTranslator.d.ts +11 -0
  177. package/dist/core/scvalTranslator.d.ts.map +1 -0
  178. package/dist/core/scvalTranslator.js +36 -0
  179. package/dist/core/scvalTranslator.js.map +1 -0
  180. package/dist/core/state_diff.d.ts +45 -0
  181. package/dist/core/state_diff.d.ts.map +1 -0
  182. package/dist/core/state_diff.js +112 -0
  183. package/dist/core/state_diff.js.map +1 -0
  184. package/dist/core/status.d.ts +24 -0
  185. package/dist/core/status.d.ts.map +1 -0
  186. package/dist/core/status.js +57 -0
  187. package/dist/core/status.js.map +1 -0
  188. package/dist/core/vault.d.ts +37 -0
  189. package/dist/core/vault.d.ts.map +1 -0
  190. package/dist/core/vault.js +179 -0
  191. package/dist/core/vault.js.map +1 -0
  192. package/dist/core/watch.d.ts +36 -0
  193. package/dist/core/watch.d.ts.map +1 -0
  194. package/dist/core/watch.js +176 -0
  195. package/dist/core/watch.js.map +1 -0
  196. package/dist/daemon/loop.d.ts +38 -0
  197. package/dist/daemon/loop.d.ts.map +1 -0
  198. package/dist/daemon/loop.js +169 -0
  199. package/dist/daemon/loop.js.map +1 -0
  200. package/dist/db/backup.d.ts +12 -0
  201. package/dist/db/backup.d.ts.map +1 -0
  202. package/dist/db/backup.js +132 -0
  203. package/dist/db/backup.js.map +1 -0
  204. package/dist/db/budget.d.ts +17 -0
  205. package/dist/db/budget.d.ts.map +1 -0
  206. package/dist/db/budget.js +31 -0
  207. package/dist/db/budget.js.map +1 -0
  208. package/dist/db/database.d.ts +6 -0
  209. package/dist/db/database.d.ts.map +1 -0
  210. package/dist/db/database.js +134 -0
  211. package/dist/db/database.js.map +1 -0
  212. package/dist/db/migrations/.gitkeep +1 -0
  213. package/dist/db/migrations/001_resource_usage_logs.sql +28 -0
  214. package/dist/db/migrator.d.ts +28 -0
  215. package/dist/db/migrator.d.ts.map +1 -0
  216. package/dist/db/migrator.js +75 -0
  217. package/dist/db/migrator.js.map +1 -0
  218. package/dist/db/repositories.d.ts +474 -0
  219. package/dist/db/repositories.d.ts.map +1 -0
  220. package/dist/db/repositories.js +809 -0
  221. package/dist/db/repositories.js.map +1 -0
  222. package/dist/db/schema.sql +207 -0
  223. package/dist/index.d.ts +3 -0
  224. package/dist/index.d.ts.map +1 -0
  225. package/dist/index.js +47 -0
  226. package/dist/index.js.map +1 -0
  227. package/dist/lib.d.ts +20 -0
  228. package/dist/lib.d.ts.map +1 -0
  229. package/dist/lib.js +16 -0
  230. package/dist/lib.js.map +1 -0
  231. package/dist/logging/index.d.ts +22 -0
  232. package/dist/logging/index.d.ts.map +1 -0
  233. package/dist/logging/index.js +34 -0
  234. package/dist/logging/index.js.map +1 -0
  235. package/dist/logging/logger.d.ts +14 -0
  236. package/dist/logging/logger.d.ts.map +1 -0
  237. package/dist/logging/logger.js +135 -0
  238. package/dist/logging/logger.js.map +1 -0
  239. package/dist/logging/types.d.ts +10 -0
  240. package/dist/logging/types.d.ts.map +1 -0
  241. package/dist/logging/types.js +2 -0
  242. package/dist/logging/types.js.map +1 -0
  243. package/dist/mcp/index.d.ts +3 -0
  244. package/dist/mcp/index.d.ts.map +1 -0
  245. package/dist/mcp/index.js +14 -0
  246. package/dist/mcp/index.js.map +1 -0
  247. package/dist/mcp/server.d.ts +10 -0
  248. package/dist/mcp/server.d.ts.map +1 -0
  249. package/dist/mcp/server.js +51 -0
  250. package/dist/mcp/server.js.map +1 -0
  251. package/dist/mcp/tools/get-extension-costs.d.ts +4 -0
  252. package/dist/mcp/tools/get-extension-costs.d.ts.map +1 -0
  253. package/dist/mcp/tools/get-extension-costs.js +33 -0
  254. package/dist/mcp/tools/get-extension-costs.js.map +1 -0
  255. package/dist/mcp/tools/get_contract_status.d.ts +8 -0
  256. package/dist/mcp/tools/get_contract_status.d.ts.map +1 -0
  257. package/dist/mcp/tools/get_contract_status.js +33 -0
  258. package/dist/mcp/tools/get_contract_status.js.map +1 -0
  259. package/dist/rpc/client.d.ts +154 -0
  260. package/dist/rpc/client.d.ts.map +1 -0
  261. package/dist/rpc/client.js +766 -0
  262. package/dist/rpc/client.js.map +1 -0
  263. package/dist/utils/config.d.ts +51 -0
  264. package/dist/utils/config.d.ts.map +1 -0
  265. package/dist/utils/config.js +86 -0
  266. package/dist/utils/config.js.map +1 -0
  267. package/dist/utils/formatting.d.ts +10 -0
  268. package/dist/utils/formatting.d.ts.map +1 -0
  269. package/dist/utils/formatting.js +66 -0
  270. package/dist/utils/formatting.js.map +1 -0
  271. package/dist/utils/watch-config.d.ts +13 -0
  272. package/dist/utils/watch-config.d.ts.map +1 -0
  273. package/dist/utils/watch-config.js +32 -0
  274. package/dist/utils/watch-config.js.map +1 -0
  275. package/package.json +73 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alerts.d.ts","sourceRoot":"","sources":["../../src/commands/alerts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiBpC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAiS5D"}
@@ -0,0 +1,256 @@
1
+ import chalk from "chalk";
2
+ import { randomBytes } from "node:crypto";
3
+ import { getDatabase } from "../db/database.js";
4
+ import { insertAlertConfig, getAlertConfigsForContract, getAlertConfigById, deleteAlertConfig, insertResourceAlertConfig, getContract, getAlertHistory, } from "../db/repositories.js";
5
+ import { formatContractID, formatTimeToCloseLedger } from "../utils/formatting.js";
6
+ import { deliverSingleAlert } from "../alerts/dispatcher.js";
7
+ import { buildAlertEvent } from "../alerts/types.js";
8
+ export function registerAlertsCommand(program) {
9
+ const alerts = program
10
+ .command("alerts")
11
+ .description("Manage alert configurations");
12
+ // ── alerts add ─────────────────────────────────────────────────────
13
+ alerts
14
+ .command("add")
15
+ .description("Add a new alert configuration (TTL-based or resource-based)")
16
+ .requiredOption("--contract <id>", "The contract ID to alert on")
17
+ .requiredOption("--type <type>", "The notification channel type ('webhook', 'slack', 'discord', 'telegram', or 'pagerduty')")
18
+ .option("--url <url>", "Webhook URL (required if --type is webhook or discord)")
19
+ .option("--channel <channel>", "Slack channel (required if --type is slack)")
20
+ .option("--routing-key <key>", "PagerDuty integration key (required if --type is pagerduty)")
21
+ .option("--secret <secret>", "HMAC secret for webhook signing (auto-generated if omitted for webhooks)")
22
+ .option("--threshold <ledgers>", "Threshold in number of ledgers (for TTL-based alerts)", (val) => parseInt(val, 10))
23
+ .option("--cpu-limit <instructions>", "CPU instruction limit for resource alerts (default: 100,000,000)", (val) => parseInt(val, 10))
24
+ .option("--mem-limit <bytes>", "Memory byte limit for resource alerts (default: 50,000,000)", (val) => parseInt(val, 10))
25
+ .action((options) => {
26
+ const contractId = options.contract;
27
+ // Determine if this is a TTL alert or resource alert
28
+ const isTTLAlert = typeof options.threshold !== "undefined";
29
+ const isResourceAlert = typeof options.cpuLimit !== "undefined" || typeof options.memLimit !== "undefined";
30
+ if (!isTTLAlert && !isResourceAlert) {
31
+ console.error(chalk.red("Error: You must specify either --threshold (for TTL alerts) or --cpu-limit/--mem-limit (for resource alerts)."));
32
+ process.exit(1);
33
+ }
34
+ if (isTTLAlert && isResourceAlert) {
35
+ console.error(chalk.red("Error: Cannot mix TTL alerts and resource alerts. Use either --threshold or --cpu-limit/--mem-limit, not both."));
36
+ process.exit(1);
37
+ }
38
+ const db = getDatabase();
39
+ const contract = getContract(db, contractId);
40
+ if (!contract) {
41
+ console.error(chalk.red(`Error: Contract ${formatContractID(contractId)} is not registered.`));
42
+ console.error(chalk.dim("Run 'sorokeep watch <contractId>' first."));
43
+ process.exit(1);
44
+ }
45
+ let target = "";
46
+ let webhookSecret;
47
+ if (options.type === "webhook") {
48
+ if (!options.url) {
49
+ console.error(chalk.red("Error: --url is required when --type is webhook."));
50
+ process.exit(1);
51
+ }
52
+ target = options.url;
53
+ webhookSecret = options.secret ?? randomBytes(32).toString("hex");
54
+ }
55
+ else if (options.type === "slack") {
56
+ if (!options.channel) {
57
+ console.error(chalk.red("Error: --channel is required when --type is slack."));
58
+ process.exit(1);
59
+ }
60
+ target = options.channel;
61
+ }
62
+ else if (options.type === "pagerduty") {
63
+ if (!options.routingKey) {
64
+ console.error(chalk.red("Error: --routing-key is required when --type is pagerduty."));
65
+ process.exit(1);
66
+ }
67
+ target = options.routingKey;
68
+ }
69
+ else if (options.type === "discord") {
70
+ if (!options.url) {
71
+ console.error(chalk.red("Error: --url is required when --type is discord. Paste the full Discord webhook URL."));
72
+ process.exit(1);
73
+ }
74
+ target = options.url;
75
+ }
76
+ else if (options.type === "telegram") {
77
+ if (!options.channel) {
78
+ console.error(chalk.red("Error: --channel is required when --type is telegram (use chat ID or @channelname)."));
79
+ process.exit(1);
80
+ }
81
+ target = options.channel;
82
+ }
83
+ else if (options.type === "email") {
84
+ console.error(chalk.red("Error: Email alerting is not yet implemented. Use 'webhook', 'slack', 'discord', 'telegram', or 'pagerduty'."));
85
+ process.exit(1);
86
+ }
87
+ else {
88
+ console.error(chalk.red("Error: --type must be 'webhook', 'slack', 'discord', 'telegram', or 'pagerduty'."));
89
+ process.exit(1);
90
+ }
91
+ if (isTTLAlert) {
92
+ const threshold = options.threshold;
93
+ if (isNaN(threshold) || threshold <= 0) {
94
+ console.error(chalk.red("Error: --threshold must be a positive integer."));
95
+ process.exit(1);
96
+ }
97
+ insertAlertConfig(db, {
98
+ contract_id: contractId,
99
+ channel_type: options.type,
100
+ channel_target: target,
101
+ threshold_ledgers: threshold,
102
+ webhook_secret: webhookSecret,
103
+ });
104
+ console.log(chalk.green(`Successfully added alert config: type=${options.type}, target=${target}, threshold=${threshold} ledgers`));
105
+ if (webhookSecret) {
106
+ console.log(` ${chalk.bold("Webhook secret:")} ${webhookSecret}`);
107
+ console.log(chalk.dim(" Save this secret — it signs payloads via X-Sorokeep-Signature header."));
108
+ }
109
+ }
110
+ else {
111
+ // Resource alert
112
+ const cpuLimit = options.cpuLimit ?? 100_000_000;
113
+ const memLimit = options.memLimit ?? 50_000_000;
114
+ if (cpuLimit <= 0 || memLimit <= 0) {
115
+ console.error(chalk.red("Error: --cpu-limit and --mem-limit must be positive integers."));
116
+ process.exit(1);
117
+ }
118
+ insertResourceAlertConfig(db, {
119
+ contract_id: contractId,
120
+ channel_type: options.type,
121
+ channel_target: target,
122
+ cpu_limit: cpuLimit,
123
+ mem_limit: memLimit,
124
+ webhook_secret: webhookSecret,
125
+ });
126
+ console.log(chalk.green(`Successfully added alert config: type=${options.type}, target=${target}, CPU=${cpuLimit.toLocaleString()} instr, MEM=${memLimit.toLocaleString()} bytes`));
127
+ if (webhookSecret) {
128
+ console.log(` ${chalk.bold("Webhook secret:")} ${webhookSecret}`);
129
+ console.log(chalk.dim(" Save this secret — it signs payloads via X-Sorokeep-Signature header."));
130
+ }
131
+ }
132
+ });
133
+ // ── alerts list ────────────────────────────────────────────────────
134
+ alerts
135
+ .command("list")
136
+ .description("List alert configurations for a contract")
137
+ .requiredOption("--contract <id>", "The contract ID to list alerts for")
138
+ .action((options) => {
139
+ const contractId = options.contract;
140
+ const db = getDatabase();
141
+ const contract = getContract(db, contractId);
142
+ if (!contract) {
143
+ console.error(chalk.red(`Error: Contract ${formatContractID(contractId)} is not registered.`));
144
+ process.exit(1);
145
+ }
146
+ const configs = getAlertConfigsForContract(db, contractId);
147
+ if (configs.length === 0) {
148
+ console.log(chalk.yellow(`No alert configurations found for contract ${formatContractID(contractId)}.`));
149
+ return;
150
+ }
151
+ console.log();
152
+ console.log(chalk.bold(` Alert Configurations for ${contract.name ?? formatContractID(contractId)}`));
153
+ console.log();
154
+ for (const config of configs) {
155
+ const signed = config.webhook_secret ? chalk.green(" [signed]") : "";
156
+ console.log(` ID: ${chalk.cyan(config.id.toString().padEnd(4))} | ` +
157
+ `Type: ${chalk.yellow(config.channel_type.padEnd(8))} | ` +
158
+ `Target: ${chalk.green(config.channel_target.padEnd(30))} | ` +
159
+ `Threshold: ${chalk.magenta(config.threshold_ledgers.toLocaleString())} ledgers` +
160
+ signed);
161
+ }
162
+ console.log();
163
+ });
164
+ // ── alerts remove ──────────────────────────────────────────────────
165
+ alerts
166
+ .command("remove")
167
+ .description("Remove an alert configuration")
168
+ .requiredOption("--id <id>", "The alert configuration ID to remove")
169
+ .action((options) => {
170
+ const id = parseInt(options.id, 10);
171
+ if (isNaN(id)) {
172
+ console.error(chalk.red("Error: --id must be a number."));
173
+ process.exit(1);
174
+ }
175
+ const db = getDatabase();
176
+ deleteAlertConfig(db, id);
177
+ console.log(chalk.green(`Successfully removed alert config ID ${id}.`));
178
+ });
179
+ // ── alerts test ────────────────────────────────────────────────────
180
+ alerts
181
+ .command("test")
182
+ .description("Send a test alert to verify channel connectivity")
183
+ .requiredOption("--id <id>", "The alert configuration ID to test")
184
+ .action(async (options) => {
185
+ const id = parseInt(options.id, 10);
186
+ if (isNaN(id)) {
187
+ console.error(chalk.red("Error: --id must be a number."));
188
+ process.exit(1);
189
+ }
190
+ const db = getDatabase();
191
+ const config = getAlertConfigById(db, id);
192
+ if (!config) {
193
+ console.error(chalk.red(`Error: Alert config ID ${id} not found.`));
194
+ process.exit(1);
195
+ }
196
+ const testEvent = buildAlertEvent({
197
+ type: "threshold_crossed",
198
+ contractId: config.contract_id,
199
+ contractName: null,
200
+ network: "testnet",
201
+ entryKeyXdr: "TEST_ENTRY_KEY",
202
+ entryType: "instance",
203
+ entryLabel: "test-entry",
204
+ configuredLedgers: config.threshold_ledgers,
205
+ remainingTTL: Math.floor(config.threshold_ledgers * 0.5),
206
+ firedAtLedger: 0,
207
+ });
208
+ console.log(`Sending test alert to ${config.channel_type}:${config.channel_target}...`);
209
+ const success = await deliverSingleAlert(config.channel_type, config.channel_target, testEvent, config.webhook_secret);
210
+ if (success) {
211
+ console.log(chalk.green("Test alert delivered successfully."));
212
+ }
213
+ else {
214
+ console.error(chalk.red("Test alert delivery failed. Check logs for details."));
215
+ process.exit(1);
216
+ }
217
+ });
218
+ // ── alerts history ─────────────────────────────────────────────────
219
+ alerts
220
+ .command("history")
221
+ .description("Show alert history for a contract")
222
+ .requiredOption("--contract <id>", "The contract ID to show history for")
223
+ .option("--limit <n>", "Max number of records to show", "20")
224
+ .action((options) => {
225
+ const contractId = options.contract;
226
+ const limit = parseInt(options.limit, 10);
227
+ const db = getDatabase();
228
+ const contract = getContract(db, contractId);
229
+ if (!contract) {
230
+ console.error(chalk.red(`Error: Contract ${formatContractID(contractId)} is not registered.`));
231
+ process.exit(1);
232
+ }
233
+ const history = getAlertHistory(db, contractId, limit > 0 ? limit : undefined);
234
+ if (history.length === 0) {
235
+ console.log(chalk.yellow("No alert history found."));
236
+ return;
237
+ }
238
+ const displayName = contract.name ?? formatContractID(contractId);
239
+ console.log(`\n${chalk.bold("Alert History")} — ${chalk.cyan(displayName)}\n`);
240
+ for (const record of history) {
241
+ const statusIcon = record.resolved ? chalk.green("✓") : chalk.yellow("●");
242
+ const deliveryIcon = record.delivered ? chalk.green("✓") : chalk.red("✗");
243
+ const label = record.entryLabel ?? record.entryType;
244
+ const ttlDisplay = formatTimeToCloseLedger(record.ttlAtFire);
245
+ console.log(` ${statusIcon} ${chalk.dim(record.firedAt)} | ` +
246
+ `${label} | TTL: ${record.ttlAtFire.toLocaleString()} (${ttlDisplay}) | ` +
247
+ `${record.channelType}→${deliveryIcon} | ` +
248
+ `retries: ${record.retryCount}`);
249
+ if (record.resolvedAt) {
250
+ console.log(chalk.dim(` Resolved: ${record.resolvedAt}`));
251
+ }
252
+ }
253
+ console.log();
254
+ });
255
+ }
256
+ //# sourceMappingURL=alerts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alerts.js","sourceRoot":"","sources":["../../src/commands/alerts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EACH,iBAAiB,EACjB,0BAA0B,EAC1B,kBAAkB,EAClB,iBAAiB,EACjB,yBAAyB,EACzB,WAAW,EACX,eAAe,GAClB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACnF,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IAClD,MAAM,MAAM,GAAG,OAAO;SACjB,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,6BAA6B,CAAC,CAAC;IAEhD,sEAAsE;IACtE,MAAM;SACD,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CAAC,6DAA6D,CAAC;SAC1E,cAAc,CAAC,iBAAiB,EAAE,6BAA6B,CAAC;SAChE,cAAc,CAAC,eAAe,EAAE,2FAA2F,CAAC;SAC5H,MAAM,CAAC,aAAa,EAAE,wDAAwD,CAAC;SAC/E,MAAM,CAAC,qBAAqB,EAAE,6CAA6C,CAAC;SAC5E,MAAM,CAAC,qBAAqB,EAAE,6DAA6D,CAAC;SAC5F,MAAM,CAAC,mBAAmB,EAAE,0EAA0E,CAAC;SACvG,MAAM,CAAC,uBAAuB,EAAE,uDAAuD,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;SACpH,MAAM,CAAC,4BAA4B,EAAE,kEAAkE,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;SACpI,MAAM,CAAC,qBAAqB,EAAE,6DAA6D,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;SACxH,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE;QAChB,MAAM,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC;QAEpC,qDAAqD;QACrD,MAAM,UAAU,GAAG,OAAO,OAAO,CAAC,SAAS,KAAK,WAAW,CAAC;QAC5D,MAAM,eAAe,GAAG,OAAO,OAAO,CAAC,QAAQ,KAAK,WAAW,IAAI,OAAO,OAAO,CAAC,QAAQ,KAAK,WAAW,CAAC;QAE3G,IAAI,CAAC,UAAU,IAAI,CAAC,eAAe,EAAE,CAAC;YAClC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,+GAA+G,CAAC,CAAC,CAAC;YAC1I,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;QAED,IAAI,UAAU,IAAI,eAAe,EAAE,CAAC;YAChC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,gHAAgH,CAAC,CAAC,CAAC;YAC3I,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;QAED,MAAM,EAAE,GAAG,WAAW,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,WAAW,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;QAC7C,IAAI,CAAC,QAAQ,EAAE,CAAC;YACZ,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,mBAAmB,gBAAgB,CAAC,UAAU,CAAC,qBAAqB,CAAC,CAAC,CAAC;YAC/F,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC,CAAC;YACrE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;QAED,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,aAAiC,CAAC;QAEtC,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC7B,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;gBACf,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,kDAAkD,CAAC,CAAC,CAAC;gBAC7E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACpB,CAAC;YACD,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;YACrB,aAAa,GAAG,OAAO,CAAC,MAAM,IAAI,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACtE,CAAC;aAAM,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAClC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;gBACnB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC,CAAC;gBAC/E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACpB,CAAC;YACD,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;QAC7B,CAAC;aAAM,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YACtC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;gBACtB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,4DAA4D,CAAC,CAAC,CAAC;gBACvF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACpB,CAAC;YACD,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;QAChC,CAAC;aAAM,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YACpC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;gBACf,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,sFAAsF,CAAC,CAAC,CAAC;gBACjH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACpB,CAAC;YACD,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;QACzB,CAAC;aAAM,IAAI,OAAO,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YACrC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;gBACnB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,qFAAqF,CAAC,CAAC,CAAC;gBAChH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACpB,CAAC;YACD,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;QAC7B,CAAC;aAAM,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAClC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,8GAA8G,CAAC,CAAC,CAAC;YACzI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;aAAM,CAAC;YACJ,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,kFAAkF,CAAC,CAAC,CAAC;YAC7G,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;QAED,IAAI,UAAU,EAAE,CAAC;YACb,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;YACpC,IAAI,KAAK,CAAC,SAAS,CAAC,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;gBACrC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC,CAAC;gBAC3E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACpB,CAAC;YAED,iBAAiB,CAAC,EAAE,EAAE;gBAClB,WAAW,EAAE,UAAU;gBACvB,YAAY,EAAE,OAAO,CAAC,IAAI;gBAC1B,cAAc,EAAE,MAAM;gBACtB,iBAAiB,EAAE,SAAS;gBAC5B,cAAc,EAAE,aAAa;aAChC,CAAC,CAAC;YAEH,OAAO,CAAC,GAAG,CACP,KAAK,CAAC,KAAK,CACP,yCAAyC,OAAO,CAAC,IAAI,YAAY,MAAM,eAAe,SAAS,UAAU,CAC5G,CACJ,CAAC;YAEF,IAAI,aAAa,EAAE,CAAC;gBAChB,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,aAAa,EAAE,CAAC,CAAC;gBACnE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,yEAAyE,CAAC,CAAC,CAAC;YACtG,CAAC;QACL,CAAC;aAAM,CAAC;YACJ,iBAAiB;YACjB,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,WAAW,CAAC;YACjD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,UAAU,CAAC;YAEhD,IAAI,QAAQ,IAAI,CAAC,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;gBACjC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,+DAA+D,CAAC,CAAC,CAAC;gBAC1F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACpB,CAAC;YAED,yBAAyB,CAAC,EAAE,EAAE;gBAC1B,WAAW,EAAE,UAAU;gBACvB,YAAY,EAAE,OAAO,CAAC,IAAI;gBAC1B,cAAc,EAAE,MAAM;gBACtB,SAAS,EAAE,QAAQ;gBACnB,SAAS,EAAE,QAAQ;gBACnB,cAAc,EAAE,aAAa;aAChC,CAAC,CAAC;YAEH,OAAO,CAAC,GAAG,CACP,KAAK,CAAC,KAAK,CACP,yCAAyC,OAAO,CAAC,IAAI,YAAY,MAAM,SAAS,QAAQ,CAAC,cAAc,EAAE,eAAe,QAAQ,CAAC,cAAc,EAAE,QAAQ,CAC5J,CACJ,CAAC;YAEF,IAAI,aAAa,EAAE,CAAC;gBAChB,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,aAAa,EAAE,CAAC,CAAC;gBACnE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,yEAAyE,CAAC,CAAC,CAAC;YACtG,CAAC;QACL,CAAC;IACL,CAAC,CAAC,CAAC;IAEP,sEAAsE;IACtE,MAAM;SACD,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,0CAA0C,CAAC;SACvD,cAAc,CAAC,iBAAiB,EAAE,oCAAoC,CAAC;SACvE,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE;QAChB,MAAM,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC;QACpC,MAAM,EAAE,GAAG,WAAW,EAAE,CAAC;QAEzB,MAAM,QAAQ,GAAG,WAAW,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;QAC7C,IAAI,CAAC,QAAQ,EAAE,CAAC;YACZ,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,mBAAmB,gBAAgB,CAAC,UAAU,CAAC,qBAAqB,CAAC,CAAC,CAAC;YAC/F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;QAED,MAAM,OAAO,GAAG,0BAA0B,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;QAC3D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,8CAA8C,gBAAgB,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;YACzG,OAAO;QACX,CAAC;QAED,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,8BAA8B,QAAQ,CAAC,IAAI,IAAI,gBAAgB,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC;QACvG,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC3B,MAAM,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACrE,OAAO,CAAC,GAAG,CACP,SAAS,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;gBACxD,SAAS,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;gBACzD,WAAW,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,KAAK;gBAC7D,cAAc,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAC,cAAc,EAAE,CAAC,UAAU;gBAChF,MAAM,CACT,CAAC;QACN,CAAC;QACD,OAAO,CAAC,GAAG,EAAE,CAAC;IAClB,CAAC,CAAC,CAAC;IAEP,sEAAsE;IACtE,MAAM;SACD,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,+BAA+B,CAAC;SAC5C,cAAc,CAAC,WAAW,EAAE,sCAAsC,CAAC;SACnE,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE;QAChB,MAAM,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACpC,IAAI,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;YACZ,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC,CAAC;YAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;QAED,MAAM,EAAE,GAAG,WAAW,EAAE,CAAC;QACzB,iBAAiB,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,wCAAwC,EAAE,GAAG,CAAC,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEP,sEAAsE;IACtE,MAAM;SACD,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,kDAAkD,CAAC;SAC/D,cAAc,CAAC,WAAW,EAAE,oCAAoC,CAAC;SACjE,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;QACtB,MAAM,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACpC,IAAI,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;YACZ,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC,CAAC;YAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;QAED,MAAM,EAAE,GAAG,WAAW,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,kBAAkB,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAC1C,IAAI,CAAC,MAAM,EAAE,CAAC;YACV,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,0BAA0B,EAAE,aAAa,CAAC,CAAC,CAAC;YACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;QAED,MAAM,SAAS,GAAG,eAAe,CAAC;YAC9B,IAAI,EAAE,mBAAmB;YACzB,UAAU,EAAE,MAAM,CAAC,WAAW;YAC9B,YAAY,EAAE,IAAI;YAClB,OAAO,EAAE,SAAS;YAClB,WAAW,EAAE,gBAAgB;YAC7B,SAAS,EAAE,UAAU;YACrB,UAAU,EAAE,YAAY;YACxB,iBAAiB,EAAE,MAAM,CAAC,iBAAiB;YAC3C,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,iBAAiB,GAAG,GAAG,CAAC;YACxD,aAAa,EAAE,CAAC;SACnB,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,yBAAyB,MAAM,CAAC,YAAY,IAAI,MAAM,CAAC,cAAc,KAAK,CAAC,CAAC;QAExF,MAAM,OAAO,GAAG,MAAM,kBAAkB,CACpC,MAAM,CAAC,YAAY,EACnB,MAAM,CAAC,cAAc,EACrB,SAAS,EACT,MAAM,CAAC,cAAc,CACxB,CAAC;QAEF,IAAI,OAAO,EAAE,CAAC;YACV,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC,CAAC;QACnE,CAAC;aAAM,CAAC;YACJ,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC,CAAC;YAChF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;IACL,CAAC,CAAC,CAAC;IAEP,sEAAsE;IACtE,MAAM;SACD,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,mCAAmC,CAAC;SAChD,cAAc,CAAC,iBAAiB,EAAE,qCAAqC,CAAC;SACxE,MAAM,CAAC,aAAa,EAAE,+BAA+B,EAAE,IAAI,CAAC;SAC5D,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE;QAChB,MAAM,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC;QACpC,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC1C,MAAM,EAAE,GAAG,WAAW,EAAE,CAAC;QAEzB,MAAM,QAAQ,GAAG,WAAW,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;QAC7C,IAAI,CAAC,QAAQ,EAAE,CAAC;YACZ,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,mBAAmB,gBAAgB,CAAC,UAAU,CAAC,qBAAqB,CAAC,CAAC,CAAC;YAC/F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;QAED,MAAM,OAAO,GAAG,eAAe,CAAC,EAAE,EAAE,UAAU,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAC/E,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,yBAAyB,CAAC,CAAC,CAAC;YACrD,OAAO;QACX,CAAC;QAED,MAAM,WAAW,GAAG,QAAQ,CAAC,IAAI,IAAI,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAClE,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAE/E,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC3B,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC1E,MAAM,YAAY,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC1E,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,SAAS,CAAC;YACpD,MAAM,UAAU,GAAG,uBAAuB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YAE7D,OAAO,CAAC,GAAG,CACP,KAAK,UAAU,IAAI,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK;gBACjD,GAAG,KAAK,WAAW,MAAM,CAAC,SAAS,CAAC,cAAc,EAAE,KAAK,UAAU,MAAM;gBACzE,GAAG,MAAM,CAAC,WAAW,IAAI,YAAY,KAAK;gBAC1C,YAAY,MAAM,CAAC,UAAU,EAAE,CAClC,CAAC;YACF,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;gBACpB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,iBAAiB,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;YACjE,CAAC;QACL,CAAC;QACD,OAAO,CAAC,GAAG,EAAE,CAAC;IAClB,CAAC,CAAC,CAAC;AACX,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function registerBudgetCommand(program: Command): void;
3
+ //# sourceMappingURL=budget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.d.ts","sourceRoot":"","sources":["../../src/commands/budget.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAkD5D"}
@@ -0,0 +1,47 @@
1
+ import chalk from "chalk";
2
+ import { getDatabase } from "../db/database.js";
3
+ import { setContractBudget, getMonthlySpendProgress } from "../core/budget.js";
4
+ import { formatContractID } from "../utils/formatting.js";
5
+ export function registerBudgetCommand(program) {
6
+ const budgetCmd = program
7
+ .command("budget")
8
+ .description("Manage monthly spending bounds for contracts");
9
+ budgetCmd
10
+ .command("set")
11
+ .description("Set a monthly budget limit for a contract")
12
+ .requiredOption("--contract <contractId>", "Contract ID to set budget for")
13
+ .requiredOption("--limit <limit>", "Monthly limit in XLM", parseFloat)
14
+ .action((options) => {
15
+ const db = getDatabase();
16
+ if (isNaN(options.limit) || options.limit < 0) {
17
+ console.log(chalk.red("Invalid limit. Must be a positive number."));
18
+ process.exit(1);
19
+ }
20
+ setContractBudget(db, options.contract, options.limit);
21
+ console.log(chalk.green(`Budget set to ${options.limit} XLM for ${formatContractID(options.contract)}.`));
22
+ });
23
+ budgetCmd
24
+ .command("status <contractId>")
25
+ .description("View current budget status and spend progress")
26
+ .action((contractId) => {
27
+ const db = getDatabase();
28
+ const progress = getMonthlySpendProgress(db, contractId);
29
+ if (!progress) {
30
+ console.log(chalk.yellow(`No budget configured for ${formatContractID(contractId)}.`));
31
+ process.exit(0);
32
+ return;
33
+ }
34
+ const { limit, spend, percentage } = progress;
35
+ console.log();
36
+ console.log(chalk.bold(` Budget Status`) + chalk.dim(` (${formatContractID(contractId)})`));
37
+ // Draw progress bar
38
+ const barWidth = 40;
39
+ const filledWidth = Math.min(barWidth, Math.floor((percentage / 100) * barWidth));
40
+ const emptyWidth = barWidth - filledWidth;
41
+ const bar = chalk.green("█".repeat(filledWidth)) + chalk.dim("░".repeat(emptyWidth));
42
+ console.log(` ${bar} ${percentage.toFixed(1)}%`);
43
+ console.log(` ${spend.toFixed(2)} / ${limit.toFixed(2)} XLM spent this month`);
44
+ console.log();
45
+ });
46
+ }
47
+ //# sourceMappingURL=budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.js","sourceRoot":"","sources":["../../src/commands/budget.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function registerChannelsCommand(program: Command): void;
3
+ //# sourceMappingURL=channels.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channels.d.ts","sourceRoot":"","sources":["../../src/commands/channels.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAiG9D"}
@@ -0,0 +1,84 @@
1
+ import chalk from "chalk";
2
+ import { getDatabase } from "../db/database.js";
3
+ import { getChannelAccounts } from "../db/repositories.js";
4
+ import { addChannel, fundChannels } from "../core/channels.js";
5
+ import { formatContractID } from "../utils/formatting.js";
6
+ export function registerChannelsCommand(program) {
7
+ const channels = program
8
+ .command("channels")
9
+ .description("Manage channel accounts for fee bumping and transaction parallelism");
10
+ // ── channels add ────────────────────────────────────────────────────────
11
+ channels
12
+ .command("add")
13
+ .description("Register a channel account public key")
14
+ .requiredOption("--key <publicKey>", "Stellar public key of the channel account")
15
+ .option("--label <label>", "Optional human-readable label")
16
+ .option("--network <network>", "Network (testnet or mainnet)", "testnet")
17
+ .action((options) => {
18
+ const db = getDatabase();
19
+ const existing = getChannelAccounts(db, options.network)
20
+ .find((a) => a.public_key === options.key);
21
+ if (existing) {
22
+ console.error(chalk.red(`Error: Key ${formatContractID(options.key)} is already registered.`));
23
+ process.exit(1);
24
+ }
25
+ addChannel(db, options.key, options.network, options.label);
26
+ console.log(chalk.green(`✔ Channel account registered successfully.`) +
27
+ `\n Key: ${chalk.cyan(options.key)}` +
28
+ (options.label ? `\n Label: ${options.label}` : "") +
29
+ `\n Network: ${options.network}`);
30
+ });
31
+ // ── channels list ───────────────────────────────────────────────────────
32
+ channels
33
+ .command("list")
34
+ .description("List registered channel accounts")
35
+ .option("--network <network>", "Network (testnet or mainnet)", "testnet")
36
+ .action((options) => {
37
+ const db = getDatabase();
38
+ const accounts = getChannelAccounts(db, options.network);
39
+ if (accounts.length === 0) {
40
+ console.log(chalk.yellow(`No channel accounts registered for network: ${options.network}.`));
41
+ return;
42
+ }
43
+ console.log();
44
+ console.log(chalk.bold(` Channel Accounts (${options.network})`));
45
+ console.log();
46
+ for (const account of accounts) {
47
+ const fundedBadge = account.funded ? chalk.green(" [funded]") : chalk.dim(" [unfunded]");
48
+ const label = account.label ? chalk.yellow(` ${account.label}`) : "";
49
+ console.log(` ${chalk.cyan(account.public_key)}${label}${fundedBadge}`);
50
+ }
51
+ console.log();
52
+ });
53
+ // ── channels fund ───────────────────────────────────────────────────────
54
+ channels
55
+ .command("fund")
56
+ .description("Send XLM from master wallet to all registered channel accounts")
57
+ .requiredOption("--master-key <secretKey>", "Master wallet secret key (source of funds)")
58
+ .option("--amount <xlm>", "Amount of XLM to send to each channel account", "10")
59
+ .option("--network <network>", "Network (testnet or mainnet)", "testnet")
60
+ .option("-r, --rpc-url <url>", "Custom RPC endpoint URL")
61
+ .action(async (options) => {
62
+ const db = getDatabase();
63
+ const accounts = getChannelAccounts(db, options.network);
64
+ if (accounts.length === 0) {
65
+ console.error(chalk.red(`No channel accounts registered for network: ${options.network}.`));
66
+ console.error(chalk.dim("Run 'sorokeep channels add --key <key>' first."));
67
+ process.exit(1);
68
+ }
69
+ console.log(`Funding ${accounts.length} channel account(s) with ${options.amount} XLM each...`);
70
+ const result = await fundChannels(db, options.masterKey, options.amount, options.network, options.rpcUrl);
71
+ if (result.errors.length > 0) {
72
+ for (const err of result.errors) {
73
+ console.error(chalk.red(`Error: ${err}`));
74
+ }
75
+ }
76
+ if (result.funded > 0) {
77
+ console.log(chalk.green(`✔ Funded ${result.funded} channel account(s) successfully.`));
78
+ if (result.txHash) {
79
+ console.log(` Tx hash: ${chalk.cyan(result.txHash)}`);
80
+ }
81
+ }
82
+ });
83
+ }
84
+ //# sourceMappingURL=channels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channels.js","sourceRoot":"","sources":["../../src/commands/channels.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function registerCheckCommand(program: Command): void;
3
+ //# sourceMappingURL=check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAmE3D"}
@@ -0,0 +1,58 @@
1
+ import chalk from "chalk";
2
+ import { getDatabase } from "../db/database.js";
3
+ import { getContract, getEntriesForContract } from "../db/repositories.js";
4
+ import { classifyTTL, statusIndicator, formatTimeToCloseLedger, formatContractID, } from "../utils/formatting.js";
5
+ export function registerCheckCommand(program) {
6
+ program
7
+ .command("check <contractId>")
8
+ .description("Check TTL health for a watched contract (CI-friendly, can be forced)")
9
+ .option("--force", "Bypass CI TTL failures and exit 0")
10
+ .requiredOption("--fail-under <ledgers>", "Exit with code 1 if any entry TTL is below this many ledgers", parseInt)
11
+ .action((contractId, options) => {
12
+ const db = getDatabase();
13
+ const contract = getContract(db, contractId);
14
+ if (!contract) {
15
+ console.log(chalk.red(`Contract ${formatContractID(contractId)} is not registered.`));
16
+ console.log(chalk.dim("Run 'sorokeep watch <contractId>' first."));
17
+ process.exit(1);
18
+ }
19
+ const entries = getEntriesForContract(db, contractId);
20
+ const lastChecked = contract.last_checked_ledger;
21
+ if (entries.length === 0 || lastChecked == null) {
22
+ console.log(chalk.green("All TTLs are safe."));
23
+ process.exit(0);
24
+ }
25
+ let hasFailure = false;
26
+ for (const entry of entries) {
27
+ if (entry.live_until_ledger == null)
28
+ continue;
29
+ const remainingTTL = entry.live_until_ledger - lastChecked;
30
+ const label = entry.entry_type === "instance"
31
+ ? "Instance"
32
+ : entry.entry_type === "wasm"
33
+ ? "WASM Code"
34
+ : entry.label ?? entry.entry_type;
35
+ const timeStr = formatTimeToCloseLedger(remainingTTL);
36
+ const status = classifyTTL(remainingTTL);
37
+ if (remainingTTL < options.failUnder) {
38
+ hasFailure = true;
39
+ console.log(`${chalk.bold(label)} TTL: ${remainingTTL.toLocaleString().padStart(9)} ledgers (${timeStr}) ${statusIndicator(status)} ${chalk.red("FAIL")}`);
40
+ }
41
+ else {
42
+ console.log(`${chalk.bold(label)} TTL: ${remainingTTL.toLocaleString().padStart(9)} ledgers (${timeStr}) ${statusIndicator(status)} ${chalk.green("PASS")}`);
43
+ }
44
+ }
45
+ if (hasFailure) {
46
+ if (options.force) {
47
+ console.log("WARNING: CI checks bypassed with --force");
48
+ process.exit(0);
49
+ }
50
+ else {
51
+ process.exit(1);
52
+ }
53
+ }
54
+ console.log(chalk.green("All TTLs are safe."));
55
+ process.exit(0);
56
+ });
57
+ }
58
+ //# sourceMappingURL=check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC3E,OAAO,EACH,WAAW,EACX,eAAe,EACf,uBAAuB,EACvB,gBAAgB,GACnB,MAAM,wBAAwB,CAAC;AAEhC,MAAM,UAAU,oBAAoB,CAAC,OAAgB;IACjD,OAAO;SACF,OAAO,CAAC,oBAAoB,CAAC;SAC7B,WAAW,CAAC,sEAAsE,CAAC;SACnF,MAAM,CAAC,SAAS,EAAE,mCAAmC,CAAC;SACtD,cAAc,CACX,wBAAwB,EACxB,8DAA8D,EAC9D,QAAQ,CACX;SACA,MAAM,CAAC,CAAC,UAAkB,EAAE,OAA+C,EAAE,EAAE;QAC5E,MAAM,EAAE,GAAG,WAAW,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,WAAW,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;QAE7C,IAAI,CAAC,QAAQ,EAAE,CAAC;YACZ,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,gBAAgB,CAAC,UAAU,CAAC,qBAAqB,CAAC,CAAC,CAAC;YACtF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC,CAAC;YACnE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;QAED,MAAM,OAAO,GAAG,qBAAqB,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;QACtD,MAAM,WAAW,GAAG,QAAQ,CAAC,mBAAmB,CAAC;QAEjD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,WAAW,IAAI,IAAI,EAAE,CAAC;YAC9C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAC;YAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;QAED,IAAI,UAAU,GAAG,KAAK,CAAC;QAEvB,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC1B,IAAI,KAAK,CAAC,iBAAiB,IAAI,IAAI;gBAAE,SAAS;YAE9C,MAAM,YAAY,GAAG,KAAK,CAAC,iBAAiB,GAAG,WAAW,CAAC;YAC3D,MAAM,KAAK,GACP,KAAK,CAAC,UAAU,KAAK,UAAU;gBAC3B,CAAC,CAAC,UAAU;gBACZ,CAAC,CAAC,KAAK,CAAC,UAAU,KAAK,MAAM;oBAC3B,CAAC,CAAC,WAAW;oBACb,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,UAAU,CAAC;YAC5C,MAAM,OAAO,GAAG,uBAAuB,CAAC,YAAY,CAAC,CAAC;YACtD,MAAM,MAAM,GAAG,WAAW,CAAC,YAAY,CAAC,CAAC;YAEzC,IAAI,YAAY,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;gBACnC,UAAU,GAAG,IAAI,CAAC;gBAClB,OAAO,CAAC,GAAG,CACP,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,YAAY,CAAC,cAAc,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,OAAO,MAAM,eAAe,CAAC,MAAM,CAAC,KAAK,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CACnJ,CAAC;YACN,CAAC;iBAAM,CAAC;gBACJ,OAAO,CAAC,GAAG,CACP,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,YAAY,CAAC,cAAc,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,OAAO,MAAM,eAAe,CAAC,MAAM,CAAC,KAAK,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CACrJ,CAAC;YACN,CAAC;QACL,CAAC;QAED,IAAI,UAAU,EAAE,CAAC;YACb,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;gBAChB,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;gBACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACpB,CAAC;iBAAM,CAAC;gBACJ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACpB,CAAC;QACL,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAC;QAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;AACX,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function registerCompletionCommand(program: Command): void;
3
+ //# sourceMappingURL=completion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion.d.ts","sourceRoot":"","sources":["../../src/commands/completion.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAkChE"}
@@ -0,0 +1,36 @@
1
+ import { getDatabase } from "../db/database.js";
2
+ import { getCompletionSuggestions, renderBashCompletionScript, renderZshCompletionScript, } from "../core/completion.js";
3
+ export function registerCompletionCommand(program) {
4
+ program
5
+ .command("completion")
6
+ .description("Generate or query shell completion suggestions")
7
+ .option("--script <shell>", "Generate a completion script for bash or zsh")
8
+ .option("--query", "Query completion suggestions for the current command line")
9
+ .option("--cursor <index>", "Cursor position for the current word", (val) => parseInt(val, 10))
10
+ .argument("[words...]", "Current command line words")
11
+ .action((words, options) => {
12
+ if (options.query) {
13
+ const cursor = Number.isInteger(options.cursor) ? options.cursor : words.length - 1;
14
+ const db = getDatabase();
15
+ const suggestions = getCompletionSuggestions(db, ["sorokeep", ...words], cursor);
16
+ process.stdout.write(suggestions.join("\n"));
17
+ return;
18
+ }
19
+ if (options.script) {
20
+ if (options.script === "bash") {
21
+ process.stdout.write(renderBashCompletionScript());
22
+ return;
23
+ }
24
+ if (options.script === "zsh") {
25
+ process.stdout.write(renderZshCompletionScript());
26
+ return;
27
+ }
28
+ console.error("Unsupported shell for completion script. Use 'bash' or 'zsh'.");
29
+ process.exit(1);
30
+ }
31
+ process.stdout.write("Generate shell completion scripts or query suggestions for shell integration.\n");
32
+ process.stdout.write("Use '--script bash' or '--script zsh' to print a completion script.\n");
33
+ process.stdout.write("Use '--query --cursor <index> [words...]' to query suggestions.\n");
34
+ });
35
+ }
36
+ //# sourceMappingURL=completion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion.js","sourceRoot":"","sources":["../../src/commands/completion.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EACL,wBAAwB,EACxB,0BAA0B,EAC1B,yBAAyB,GAC1B,MAAM,uBAAuB,CAAC;AAE/B,MAAM,UAAU,yBAAyB,CAAC,OAAgB;IACxD,OAAO;SACJ,OAAO,CAAC,YAAY,CAAC;SACrB,WAAW,CAAC,gDAAgD,CAAC;SAC7D,MAAM,CAAC,kBAAkB,EAAE,8CAA8C,CAAC;SAC1E,MAAM,CAAC,SAAS,EAAE,2DAA2D,CAAC;SAC9E,MAAM,CAAC,kBAAkB,EAAE,sCAAsC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;SAC9F,QAAQ,CAAC,YAAY,EAAE,4BAA4B,CAAC;SACpD,MAAM,CAAC,CAAC,KAAe,EAAE,OAA8D,EAAE,EAAE;QAC1F,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YAClB,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;YACrF,MAAM,EAAE,GAAG,WAAW,EAAE,CAAC;YACzB,MAAM,WAAW,GAAG,wBAAwB,CAAC,EAAE,EAAE,CAAC,UAAU,EAAE,GAAG,KAAK,CAAC,EAAE,MAAM,CAAC,CAAC;YACjF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YAC7C,OAAO;QACT,CAAC;QAED,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;gBAC9B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,EAAE,CAAC,CAAC;gBACnD,OAAO;YACT,CAAC;YACD,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;gBAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,EAAE,CAAC,CAAC;gBAClD,OAAO;YACT,CAAC;YACD,OAAO,CAAC,KAAK,CAAC,+DAA+D,CAAC,CAAC;YAC/E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iFAAiF,CAAC,CAAC;QACxG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,uEAAuE,CAAC,CAAC;QAC9F,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mEAAmE,CAAC,CAAC;IAC5F,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { Command } from "commander";
2
+ import type { RentWindowsResult } from "../core/rent_projection.js";
3
+ /**
4
+ * Render a single RentWindowsResult as a table under the "Forecasted Rent"
5
+ * section. Returns an array of console lines (without printing) so callers can
6
+ * test the output easily.
7
+ *
8
+ * @param result - Output of `projectRentWindows` for one entry.
9
+ * @param entryType - Human-readable entry type label (instance, wasm, …).
10
+ * @param budget - Monthly budget in XLM (optional). When provided, windows
11
+ * that exceed the budget are flagged in red.
12
+ */
13
+ export declare function formatForecastedRentEntry(result: RentWindowsResult, entryType: string, budget?: number): string[];
14
+ export declare function registerCostsCommand(program: Command): void;
15
+ //# sourceMappingURL=costs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"costs.d.ts","sourceRoot":"","sources":["../../src/commands/costs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAwDpE;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACrC,MAAM,EAAE,iBAAiB,EACzB,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,MAAM,GAChB,MAAM,EAAE,CAoBV;AAKD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuR3D"}