@thinremote/thinr-cli 1.2.0-alpha.1 → 1.3.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 (92) hide show
  1. package/CHANGELOG.md +63 -1
  2. package/README.md +235 -30
  3. package/bin/thinr.js +43 -25
  4. package/commands/_shared.js +154 -0
  5. package/commands/dashboard.js +17 -0
  6. package/commands/device/_shared.js +17 -34
  7. package/commands/device/console.js +1 -0
  8. package/commands/device/delete.js +53 -0
  9. package/commands/device/exec.js +7 -6
  10. package/commands/device/fs.js +193 -0
  11. package/commands/device/index.js +9 -0
  12. package/commands/device/list.js +35 -23
  13. package/commands/device/logs.js +178 -0
  14. package/commands/device/property.js +30 -28
  15. package/commands/device/proxy.js +3 -0
  16. package/commands/device/resource.js +30 -29
  17. package/commands/device/status.js +35 -14
  18. package/commands/device/transfer.js +236 -0
  19. package/commands/device/update.js +15 -10
  20. package/commands/fleet/index.js +17 -0
  21. package/commands/fleet/upgrade.js +275 -0
  22. package/commands/logout.js +10 -11
  23. package/commands/playbook/_shared.js +12 -0
  24. package/commands/playbook/index.js +18 -0
  25. package/commands/playbook/run.js +302 -0
  26. package/commands/playbook/validate.js +38 -0
  27. package/commands/product/_shared.js +8 -0
  28. package/commands/product/exec.js +243 -0
  29. package/commands/product/fs.js +218 -0
  30. package/commands/product/index.js +35 -0
  31. package/commands/product/list.js +86 -0
  32. package/commands/product/logs.js +289 -0
  33. package/commands/product/metric.js +124 -0
  34. package/commands/product/playbook.js +911 -0
  35. package/commands/product/property.js +76 -0
  36. package/commands/product/props.js +125 -0
  37. package/commands/product/push.js +184 -0
  38. package/commands/product/resource.js +76 -0
  39. package/commands/product/status.js +213 -0
  40. package/commands/profile.js +76 -8
  41. package/dist/dashboard.js +5644 -0
  42. package/lib/agent-releases.js +59 -0
  43. package/lib/agent-versions.js +73 -0
  44. package/lib/alarms.js +252 -0
  45. package/lib/api.js +8 -2
  46. package/lib/auth.js +68 -20
  47. package/lib/bucket.js +87 -0
  48. package/lib/command-stream.js +213 -0
  49. package/lib/config.js +5 -3
  50. package/lib/console.js +19 -5
  51. package/lib/constants.js +83 -0
  52. package/lib/dashboard/event-stream.js +239 -0
  53. package/lib/dashboard/metric-aggregate.js +64 -0
  54. package/lib/dashboard/metric-filter.js +39 -0
  55. package/lib/debug-log.js +93 -0
  56. package/lib/device-api.js +131 -148
  57. package/lib/devices.js +18 -21
  58. package/lib/errors.js +12 -0
  59. package/lib/fleet-upgrade.js +106 -0
  60. package/lib/format.js +114 -0
  61. package/lib/mcp/registry.js +14 -0
  62. package/lib/mcp/tools-alarms.js +510 -0
  63. package/lib/mcp/tools-buckets.js +103 -0
  64. package/lib/mcp/tools-devices.js +33 -3
  65. package/lib/mcp/tools-exec.js +30 -17
  66. package/lib/mcp/tools-filesystem.js +102 -6
  67. package/lib/mcp/tools-install.js +153 -0
  68. package/lib/mcp/tools-logs.js +225 -0
  69. package/lib/mcp/tools-playbook.js +211 -0
  70. package/lib/mcp/tools-products.js +1226 -105
  71. package/lib/mcp/tools-profile.js +634 -0
  72. package/lib/mcp/tools-tokens.js +371 -0
  73. package/lib/monitoring.js +26 -1
  74. package/lib/playbook/actions.js +447 -0
  75. package/lib/playbook/expression.js +302 -0
  76. package/lib/playbook/fleet.js +175 -0
  77. package/lib/playbook/loader.js +247 -0
  78. package/lib/playbook/runner.js +300 -0
  79. package/lib/playbook/schema.js +209 -0
  80. package/lib/playbook/vars.js +209 -0
  81. package/lib/product/log-presets.js +196 -0
  82. package/lib/product/logs.js +485 -0
  83. package/lib/product-orchestrator.js +124 -0
  84. package/lib/product.js +523 -20
  85. package/lib/profile.js +665 -0
  86. package/lib/property.js +7 -40
  87. package/lib/proxy.js +9 -8
  88. package/lib/resource.js +10 -14
  89. package/lib/status.js +78 -37
  90. package/lib/tokens.js +374 -0
  91. package/package.json +14 -3
  92. package/commands/product.js +0 -407
@@ -0,0 +1,124 @@
1
+ // @ts-check
2
+ import {
3
+ listDashboardMetrics,
4
+ upsertDashboardMetric,
5
+ removeDashboardMetric,
6
+ } from '../../lib/product.js';
7
+ import { info, success } from '../../lib/format.js';
8
+ import { isJsonMode, printOk, printErr, classifyError } from '../../lib/output.js';
9
+ import { applyJsonFlag, ensureConfigured, getGlobalUser } from '../_shared.js';
10
+
11
+ function stringifyMetricLine(m) {
12
+ const parts = [
13
+ `resource=${m.resource}`,
14
+ m.field ? `field=${m.field}` : null,
15
+ m.aggregation ? `agg=${m.aggregation}` : null,
16
+ m.visualization ? `viz=${m.visualization}` : null,
17
+ m.interval ? `every ${m.interval}s` : null,
18
+ ].filter(Boolean);
19
+ const trail = m.label ? ` · ${m.label}` : '';
20
+ return `${m.name} ${parts.join(' ')}${trail}`;
21
+ }
22
+
23
+ export function registerProductMetricCommands(product) {
24
+ product
25
+ .command('metric-list <productId>')
26
+ .helpGroup('Product config:')
27
+ .description('List dashboard metrics configured on a product')
28
+ .option('-j, --json', 'Output as JSON')
29
+ .action(async (productId, opts, cmd) => {
30
+ applyJsonFlag(opts);
31
+ ensureConfigured();
32
+ const user = getGlobalUser(cmd);
33
+ try {
34
+ const metrics = await listDashboardMetrics(productId, user);
35
+ if (isJsonMode()) {
36
+ printOk({ product: productId, metrics });
37
+ return;
38
+ }
39
+ if (metrics.length === 0) {
40
+ console.log(`No dashboard metrics configured on ${info(productId)}`);
41
+ return;
42
+ }
43
+ console.log(`${metrics.length} metric(s) on ${info(productId)}:`);
44
+ for (const m of metrics) console.log(' - ' + stringifyMetricLine(m));
45
+ } catch (error) {
46
+ const { message, code } = classifyError(error);
47
+ printErr(message, { code });
48
+ }
49
+ });
50
+
51
+ product
52
+ .command('metric-set <productId> <name>')
53
+ .helpGroup('Product config:')
54
+ .description('Add or update a dashboard metric on a product')
55
+ .requiredOption('-r, --resource <resource>', 'Product API resource the dashboard invokes')
56
+ .option('-l, --label <label>', 'Human-readable label for the metric')
57
+ .option('-f, --field <field>', 'Dot-path to the numeric value inside the response')
58
+ .option(
59
+ '-a, --aggregation <agg>',
60
+ 'Aggregation across the fleet (sum, avg, max, min, count, top, none, distribution)',
61
+ )
62
+ .option(
63
+ '-v, --visualization <viz>',
64
+ 'Dashboard rendering hint (kpi, bar, sparkline, list)',
65
+ )
66
+ .option('-i, --interval <seconds>', 'Dashboard refresh interval in seconds', Number)
67
+ .option('--unit <unit>', 'Unit suffix for display (e.g. "%", "devices")')
68
+ .option('--json', 'Output as JSON')
69
+ .action(async (productId, name, opts, cmd) => {
70
+ applyJsonFlag(opts);
71
+ ensureConfigured();
72
+ const user = getGlobalUser(cmd);
73
+ const metric = {
74
+ name,
75
+ label: opts.label,
76
+ resource: opts.resource,
77
+ field: opts.field,
78
+ aggregation: opts.aggregation,
79
+ visualization: opts.visualization,
80
+ interval: opts.interval,
81
+ unit: opts.unit,
82
+ };
83
+ for (const k of Object.keys(metric)) if (metric[k] === undefined) delete metric[k];
84
+ try {
85
+ const { action, count } = await upsertDashboardMetric(productId, metric, user);
86
+ if (isJsonMode()) {
87
+ printOk({ product: productId, action, metric, total: count });
88
+ return;
89
+ }
90
+ console.log(
91
+ `Metric ${info(name)} ${success(action)} on ${info(productId)} (total: ${count}).`,
92
+ );
93
+ } catch (error) {
94
+ const { message, code } = classifyError(error);
95
+ printErr(message, { code });
96
+ }
97
+ });
98
+
99
+ product
100
+ .command('metric-delete <productId> <name>')
101
+ .helpGroup('Product config:')
102
+ .description('Remove a dashboard metric from a product')
103
+ .option('-j, --json', 'Output as JSON')
104
+ .action(async (productId, name, opts, cmd) => {
105
+ applyJsonFlag(opts);
106
+ ensureConfigured();
107
+ const user = getGlobalUser(cmd);
108
+ try {
109
+ const { action, count } = await removeDashboardMetric(productId, name, user);
110
+ if (isJsonMode()) {
111
+ printOk({ product: productId, action, remaining: count });
112
+ return;
113
+ }
114
+ console.log(
115
+ action === 'removed'
116
+ ? `Removed ${info(name)} from ${info(productId)} (remaining: ${count}).`
117
+ : `Metric ${info(name)} was not configured on ${info(productId)}.`,
118
+ );
119
+ } catch (error) {
120
+ const { message, code } = classifyError(error);
121
+ printErr(message, { code });
122
+ }
123
+ });
124
+ }