@matthesketh/fleet 1.1.0 → 1.6.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 (217) hide show
  1. package/README.md +183 -251
  2. package/dist/adapters/detector/index.d.ts +8 -0
  3. package/dist/adapters/detector/index.js +54 -0
  4. package/dist/adapters/notifier/index.d.ts +2 -0
  5. package/dist/adapters/notifier/index.js +2 -0
  6. package/dist/adapters/notifier/stdout.d.ts +2 -0
  7. package/dist/adapters/notifier/stdout.js +8 -0
  8. package/dist/adapters/notifier/webhook.d.ts +9 -0
  9. package/dist/adapters/notifier/webhook.js +38 -0
  10. package/dist/adapters/runner/claude-cli.d.ts +7 -0
  11. package/dist/adapters/runner/claude-cli.js +231 -0
  12. package/dist/adapters/runner/mcp-call.d.ts +8 -0
  13. package/dist/adapters/runner/mcp-call.js +82 -0
  14. package/dist/adapters/runner/shell.d.ts +2 -0
  15. package/dist/adapters/runner/shell.js +103 -0
  16. package/dist/adapters/scheduler/systemd-timer.d.ts +17 -0
  17. package/dist/adapters/scheduler/systemd-timer.js +149 -0
  18. package/dist/adapters/signals/ci-status.d.ts +2 -0
  19. package/dist/adapters/signals/ci-status.js +79 -0
  20. package/dist/adapters/signals/container-up.d.ts +5 -0
  21. package/dist/adapters/signals/container-up.js +54 -0
  22. package/dist/adapters/signals/git-clean.d.ts +2 -0
  23. package/dist/adapters/signals/git-clean.js +55 -0
  24. package/dist/adapters/signals/index.d.ts +6 -0
  25. package/dist/adapters/signals/index.js +7 -0
  26. package/dist/adapters/types.d.ts +52 -0
  27. package/dist/adapters/types.js +1 -0
  28. package/dist/cli.js +43 -2
  29. package/dist/commands/add.js +0 -6
  30. package/dist/commands/boot-start.d.ts +1 -0
  31. package/dist/commands/boot-start.js +51 -0
  32. package/dist/commands/deploy.js +13 -0
  33. package/dist/commands/deps.js +5 -0
  34. package/dist/commands/egress.d.ts +1 -0
  35. package/dist/commands/egress.js +106 -0
  36. package/dist/commands/freeze.d.ts +4 -0
  37. package/dist/commands/freeze.js +64 -0
  38. package/dist/commands/logs.d.ts +1 -1
  39. package/dist/commands/logs.js +237 -8
  40. package/dist/commands/patch-systemd.d.ts +1 -0
  41. package/dist/commands/patch-systemd.js +126 -0
  42. package/dist/commands/rollback.d.ts +1 -0
  43. package/dist/commands/rollback.js +58 -0
  44. package/dist/commands/routine-run.d.ts +1 -0
  45. package/dist/commands/routine-run.js +122 -0
  46. package/dist/commands/routines.d.ts +1 -0
  47. package/dist/commands/routines.js +25 -0
  48. package/dist/commands/secrets.js +449 -16
  49. package/dist/commands/status.js +7 -3
  50. package/dist/commands/watchdog.d.ts +1 -1
  51. package/dist/commands/watchdog.js +16 -40
  52. package/dist/core/boot-refresh.d.ts +57 -0
  53. package/dist/core/boot-refresh.js +116 -0
  54. package/dist/core/deps/actors/pr-creator.js +11 -9
  55. package/dist/core/deps/collectors/docker-running.js +2 -2
  56. package/dist/core/deps/collectors/github-pr.js +5 -2
  57. package/dist/core/deps/collectors/npm.js +10 -5
  58. package/dist/core/deps/collectors/vulnerability.js +10 -6
  59. package/dist/core/deps/reporters/motd.js +1 -1
  60. package/dist/core/deps/reporters/telegram.js +2 -29
  61. package/dist/core/docker.js +45 -15
  62. package/dist/core/egress.d.ts +41 -0
  63. package/dist/core/egress.js +161 -0
  64. package/dist/core/exec.d.ts +7 -1
  65. package/dist/core/exec.js +25 -17
  66. package/dist/core/git.d.ts +1 -0
  67. package/dist/core/git.js +36 -23
  68. package/dist/core/github.js +27 -8
  69. package/dist/core/health.d.ts +3 -0
  70. package/dist/core/health.js +15 -3
  71. package/dist/core/logs-multi.d.ts +73 -0
  72. package/dist/core/logs-multi.js +163 -0
  73. package/dist/core/logs-policy.d.ts +55 -0
  74. package/dist/core/logs-policy.js +148 -0
  75. package/dist/core/nginx.js +8 -4
  76. package/dist/core/notify.d.ts +15 -0
  77. package/dist/core/notify.js +55 -0
  78. package/dist/core/registry.d.ts +25 -0
  79. package/dist/core/registry.js +57 -10
  80. package/dist/core/routines/cost-queries.d.ts +24 -0
  81. package/dist/core/routines/cost-queries.js +65 -0
  82. package/dist/core/routines/db.d.ts +9 -0
  83. package/dist/core/routines/db.js +126 -0
  84. package/dist/core/routines/defaults.d.ts +2 -0
  85. package/dist/core/routines/defaults.js +72 -0
  86. package/dist/core/routines/engine.d.ts +59 -0
  87. package/dist/core/routines/engine.js +175 -0
  88. package/dist/core/routines/incidents.d.ts +13 -0
  89. package/dist/core/routines/incidents.js +35 -0
  90. package/dist/core/routines/schema.d.ts +418 -0
  91. package/dist/core/routines/schema.js +113 -0
  92. package/dist/core/routines/signals-collector.d.ts +35 -0
  93. package/dist/core/routines/signals-collector.js +114 -0
  94. package/dist/core/routines/store.d.ts +316 -0
  95. package/dist/core/routines/store.js +99 -0
  96. package/dist/core/routines/test-utils.d.ts +2 -0
  97. package/dist/core/routines/test-utils.js +13 -0
  98. package/dist/core/secrets-audit.d.ts +21 -0
  99. package/dist/core/secrets-audit.js +60 -0
  100. package/dist/core/secrets-metadata.d.ts +39 -0
  101. package/dist/core/secrets-metadata.js +82 -0
  102. package/dist/core/secrets-motd.d.ts +20 -0
  103. package/dist/core/secrets-motd.js +72 -0
  104. package/dist/core/secrets-ops.d.ts +3 -1
  105. package/dist/core/secrets-ops.js +78 -13
  106. package/dist/core/secrets-providers.d.ts +50 -0
  107. package/dist/core/secrets-providers.js +291 -0
  108. package/dist/core/secrets-rotation.d.ts +52 -0
  109. package/dist/core/secrets-rotation.js +165 -0
  110. package/dist/core/secrets-snapshots.d.ts +26 -0
  111. package/dist/core/secrets-snapshots.js +95 -0
  112. package/dist/core/secrets-validate.js +2 -1
  113. package/dist/core/secrets.d.ts +12 -1
  114. package/dist/core/secrets.js +35 -24
  115. package/dist/core/self-update.d.ts +41 -0
  116. package/dist/core/self-update.js +73 -0
  117. package/dist/core/systemd.js +29 -12
  118. package/dist/core/telegram.d.ts +6 -0
  119. package/dist/core/telegram.js +32 -0
  120. package/dist/core/validate.d.ts +7 -0
  121. package/dist/core/validate.js +42 -0
  122. package/dist/index.js +0 -4
  123. package/dist/mcp/deps-tools.js +9 -1
  124. package/dist/mcp/git-tools.js +4 -4
  125. package/dist/mcp/server.js +193 -8
  126. package/dist/templates/systemd.js +3 -3
  127. package/dist/templates/unseal.js +5 -1
  128. package/dist/tui/components/Confirm.js +3 -4
  129. package/dist/tui/components/Header.js +37 -8
  130. package/dist/tui/components/KeyHint.js +14 -5
  131. package/dist/tui/exec-bridge.js +26 -12
  132. package/dist/tui/hooks/use-fleet-data.js +5 -2
  133. package/dist/tui/hooks/use-health.js +5 -2
  134. package/dist/tui/hooks/use-terminal-size.d.ts +1 -0
  135. package/dist/tui/hooks/use-terminal-size.js +1 -0
  136. package/dist/tui/router.js +133 -8
  137. package/dist/tui/routines/RoutinesApp.d.ts +8 -0
  138. package/dist/tui/routines/RoutinesApp.js +277 -0
  139. package/dist/tui/routines/components/AlertsPanel.d.ts +7 -0
  140. package/dist/tui/routines/components/AlertsPanel.js +22 -0
  141. package/dist/tui/routines/components/AlertsPanel.test.d.ts +1 -0
  142. package/dist/tui/routines/components/AlertsPanel.test.js +52 -0
  143. package/dist/tui/routines/components/CommandPalette.d.ts +12 -0
  144. package/dist/tui/routines/components/CommandPalette.js +21 -0
  145. package/dist/tui/routines/components/LiveRunPanel.d.ts +12 -0
  146. package/dist/tui/routines/components/LiveRunPanel.js +107 -0
  147. package/dist/tui/routines/components/RoutineForm.d.ts +8 -0
  148. package/dist/tui/routines/components/RoutineForm.js +254 -0
  149. package/dist/tui/routines/components/SignalsGrid.d.ts +13 -0
  150. package/dist/tui/routines/components/SignalsGrid.js +34 -0
  151. package/dist/tui/routines/components/SignalsGrid.test.d.ts +1 -0
  152. package/dist/tui/routines/components/SignalsGrid.test.js +43 -0
  153. package/dist/tui/routines/format.d.ts +7 -0
  154. package/dist/tui/routines/format.js +51 -0
  155. package/dist/tui/routines/hooks/use-git-fleet.d.ts +33 -0
  156. package/dist/tui/routines/hooks/use-git-fleet.js +82 -0
  157. package/dist/tui/routines/hooks/use-logs-stream.d.ts +13 -0
  158. package/dist/tui/routines/hooks/use-logs-stream.js +64 -0
  159. package/dist/tui/routines/hooks/use-ops-fleet.d.ts +20 -0
  160. package/dist/tui/routines/hooks/use-ops-fleet.js +70 -0
  161. package/dist/tui/routines/hooks/use-repo-detail.d.ts +31 -0
  162. package/dist/tui/routines/hooks/use-repo-detail.js +104 -0
  163. package/dist/tui/routines/hooks/use-security.d.ts +33 -0
  164. package/dist/tui/routines/hooks/use-security.js +110 -0
  165. package/dist/tui/routines/hooks/use-signals.d.ts +9 -0
  166. package/dist/tui/routines/hooks/use-signals.js +60 -0
  167. package/dist/tui/routines/runtime.d.ts +20 -0
  168. package/dist/tui/routines/runtime.js +40 -0
  169. package/dist/tui/routines/tabs/CostTab.d.ts +7 -0
  170. package/dist/tui/routines/tabs/CostTab.js +24 -0
  171. package/dist/tui/routines/tabs/DashboardTab.d.ts +15 -0
  172. package/dist/tui/routines/tabs/DashboardTab.js +10 -0
  173. package/dist/tui/routines/tabs/GitTab.d.ts +6 -0
  174. package/dist/tui/routines/tabs/GitTab.js +39 -0
  175. package/dist/tui/routines/tabs/LogsTab.d.ts +6 -0
  176. package/dist/tui/routines/tabs/LogsTab.js +58 -0
  177. package/dist/tui/routines/tabs/OpsTab.d.ts +6 -0
  178. package/dist/tui/routines/tabs/OpsTab.js +34 -0
  179. package/dist/tui/routines/tabs/RepoDetailView.d.ts +6 -0
  180. package/dist/tui/routines/tabs/RepoDetailView.js +12 -0
  181. package/dist/tui/routines/tabs/RoutinesTab.d.ts +10 -0
  182. package/dist/tui/routines/tabs/RoutinesTab.js +58 -0
  183. package/dist/tui/routines/tabs/ScaffoldTab.d.ts +2 -0
  184. package/dist/tui/routines/tabs/ScaffoldTab.js +127 -0
  185. package/dist/tui/routines/tabs/SecurityTab.d.ts +6 -0
  186. package/dist/tui/routines/tabs/SecurityTab.js +31 -0
  187. package/dist/tui/routines/tabs/SettingsTab.d.ts +6 -0
  188. package/dist/tui/routines/tabs/SettingsTab.js +61 -0
  189. package/dist/tui/routines/tabs/TimelineTab.d.ts +7 -0
  190. package/dist/tui/routines/tabs/TimelineTab.js +26 -0
  191. package/dist/tui/state.js +16 -1
  192. package/dist/tui/tests/flicker.test.d.ts +1 -0
  193. package/dist/tui/tests/flicker.test.js +105 -0
  194. package/dist/tui/tests/keyboard-integration.test.d.ts +1 -0
  195. package/dist/tui/tests/keyboard-integration.test.js +120 -0
  196. package/dist/tui/tests/test-app.d.ts +4 -0
  197. package/dist/tui/tests/test-app.js +79 -0
  198. package/dist/tui/types.d.ts +14 -1
  199. package/dist/tui/views/AppDetail.js +40 -26
  200. package/dist/tui/views/Dashboard.js +34 -9
  201. package/dist/tui/views/HealthView.js +42 -12
  202. package/dist/tui/views/LogsView.js +38 -10
  203. package/dist/tui/views/MultiLogsView.d.ts +2 -0
  204. package/dist/tui/views/MultiLogsView.js +165 -0
  205. package/dist/tui/views/SecretEdit.js +18 -7
  206. package/dist/tui/views/SecretsView.js +55 -39
  207. package/dist/ui/prompt.d.ts +52 -0
  208. package/dist/ui/prompt.js +169 -0
  209. package/package.json +33 -5
  210. package/dist/commands/motd.d.ts +0 -1
  211. package/dist/commands/motd.js +0 -10
  212. package/dist/templates/motd.d.ts +0 -1
  213. package/dist/templates/motd.js +0 -7
  214. package/dist/tui/components/AppList.d.ts +0 -12
  215. package/dist/tui/components/AppList.js +0 -32
  216. package/dist/tui/hooks/use-keyboard.d.ts +0 -1
  217. package/dist/tui/hooks/use-keyboard.js +0 -44
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Plain-text and hidden-input prompts, no external deps.
3
+ *
4
+ * promptHidden uses raw mode + manual char-by-char read so the echoed value
5
+ * never appears on the terminal — important for pasting secrets and for
6
+ * tools like `script` / asciinema.
7
+ */
8
+ import * as readline from 'node:readline';
9
+ export async function prompt(message, defaultValue) {
10
+ const hint = defaultValue !== undefined ? ` [${defaultValue}]` : '';
11
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
12
+ return new Promise(resolve => {
13
+ rl.question(`${message}${hint}: `, answer => {
14
+ rl.close();
15
+ const trimmed = answer.trim();
16
+ resolve(trimmed === '' && defaultValue !== undefined ? defaultValue : trimmed);
17
+ });
18
+ });
19
+ }
20
+ /**
21
+ * String variant — convenience wrapper around the Buffer variant. Use the
22
+ * Buffer variant directly if you want the strongest in-memory guarantees;
23
+ * this one converts to string and the result lives in the V8 heap until GC.
24
+ */
25
+ export async function promptHidden(message) {
26
+ const buf = await promptHiddenBuffer(message);
27
+ try {
28
+ return buf.toString('utf8');
29
+ }
30
+ finally {
31
+ buf.fill(0);
32
+ }
33
+ }
34
+ /**
35
+ * Buffer-based hidden input. Returns the raw input bytes in a Buffer the
36
+ * caller is expected to zero out (`buf.fill(0)`) when finished — see
37
+ * `withSecretBuffer` for an automated pattern.
38
+ *
39
+ * Why Buffer (not string)?
40
+ * - Node strings are immutable + interned in V8 heap; you can't zero them.
41
+ * Once a secret string exists, it sits in the heap until GC.
42
+ * - Buffer is a writable byte array. Calling `buf.fill(0)` overwrites the
43
+ * bytes in-place; subsequent heap dumps and core dumps contain zeros.
44
+ *
45
+ * Hardening:
46
+ * - Buffer is grown by `Buffer.concat` and the intermediate buffers are
47
+ * zeroed before being released.
48
+ * - Non-TTY fallback uses `terminal: false` so readline can never promote
49
+ * stdout to terminal mode and echo the value.
50
+ * - End/error/SIGINT all reject + restore terminal state and zero the
51
+ * in-flight buffer so a death never leaves bytes behind.
52
+ *
53
+ * KNOWN LIMITATION: any string copy made downstream (e.g. `buf.toString()`
54
+ * for regex validation) lives in V8 heap until GC. Convert as late as
55
+ * possible and let the string go out of scope ASAP.
56
+ */
57
+ export function promptHiddenBuffer(message) {
58
+ if (!process.stdin.isTTY) {
59
+ return new Promise((resolve, reject) => {
60
+ const rl = readline.createInterface({ input: process.stdin, terminal: false });
61
+ process.stdout.write(message + ': ');
62
+ let done = false;
63
+ const finish = (cb) => { if (done)
64
+ return; done = true; rl.close(); cb(); };
65
+ rl.once('line', line => finish(() => resolve(Buffer.from(line, 'utf8'))));
66
+ rl.once('close', () => finish(() => reject(new Error('Cancelled (stdin closed)'))));
67
+ rl.once('error', err => finish(() => reject(err)));
68
+ });
69
+ }
70
+ return new Promise((resolve, reject) => {
71
+ const stdin = process.stdin;
72
+ process.stdout.write(message + ': ');
73
+ // Pre-allocate; grow geometrically to avoid quadratic Buffer.concat.
74
+ let buf = Buffer.alloc(64);
75
+ let len = 0;
76
+ let settled = false;
77
+ const wasRaw = stdin.isRaw;
78
+ const grow = (need) => {
79
+ if (len + need <= buf.length)
80
+ return;
81
+ const next = Buffer.alloc(Math.max(buf.length * 2, len + need));
82
+ buf.copy(next);
83
+ buf.fill(0); // zero the old buffer before releasing
84
+ buf = next;
85
+ };
86
+ const cleanup = () => {
87
+ stdin.removeListener('data', onData);
88
+ stdin.removeListener('end', onEnd);
89
+ stdin.removeListener('error', onError);
90
+ process.removeListener('SIGINT', onSigint);
91
+ try {
92
+ stdin.setRawMode(wasRaw);
93
+ }
94
+ catch { /* terminal may be gone */ }
95
+ stdin.pause();
96
+ };
97
+ const settle = (fn) => {
98
+ if (settled)
99
+ return;
100
+ settled = true;
101
+ cleanup();
102
+ fn();
103
+ };
104
+ const wipeAndReject = (err) => {
105
+ buf.fill(0);
106
+ settle(() => reject(err));
107
+ };
108
+ const onData = (chunk) => {
109
+ for (let i = 0; i < chunk.length; i++) {
110
+ const c = chunk[i];
111
+ if (c === 0x0d || c === 0x0a) { // \r \n
112
+ process.stdout.write('\n');
113
+ const out = Buffer.alloc(len);
114
+ buf.copy(out, 0, 0, len);
115
+ buf.fill(0);
116
+ settle(() => resolve(out));
117
+ return;
118
+ }
119
+ else if (c === 0x03) { // Ctrl-C
120
+ process.stdout.write('\n');
121
+ wipeAndReject(new Error('Cancelled'));
122
+ return;
123
+ }
124
+ else if (c === 0x7f || c === 0x08) { // backspace
125
+ if (len > 0) {
126
+ len -= 1;
127
+ buf[len] = 0;
128
+ }
129
+ }
130
+ else if (c >= 0x20) { // printable
131
+ grow(1);
132
+ buf[len++] = c;
133
+ }
134
+ }
135
+ };
136
+ const onEnd = () => wipeAndReject(new Error('Cancelled (stdin ended)'));
137
+ const onError = (err) => wipeAndReject(err);
138
+ const onSigint = () => { process.stdout.write('\n'); wipeAndReject(new Error('Cancelled (SIGINT)')); };
139
+ stdin.setRawMode(true);
140
+ stdin.resume();
141
+ // Note: do NOT setEncoding — we want raw bytes, not auto-decoded strings.
142
+ stdin.on('data', onData);
143
+ stdin.on('end', onEnd);
144
+ stdin.on('error', onError);
145
+ process.on('SIGINT', onSigint);
146
+ });
147
+ }
148
+ /**
149
+ * Recommended pattern for handling a secret in memory: read into a Buffer,
150
+ * pass to your callback, zero on exit (success or throw). Use this instead
151
+ * of `promptHidden` when the value will be processed by code under your
152
+ * control end-to-end.
153
+ *
154
+ * Example:
155
+ * await withSecretBuffer('Paste new STRIPE_SECRET_KEY', async (buf) => {
156
+ * const asString = buf.toString('utf8'); // brief string copy
157
+ * await sealApp(app, applyRotation(...)); // age-encrypt happens here
158
+ * // String copy is unreferenced from this point; buf is zeroed on exit.
159
+ * });
160
+ */
161
+ export async function withSecretBuffer(message, fn) {
162
+ const buf = await promptHiddenBuffer(message);
163
+ try {
164
+ return await fn(buf);
165
+ }
166
+ finally {
167
+ buf.fill(0);
168
+ }
169
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@matthesketh/fleet",
3
- "version": "1.1.0",
3
+ "version": "1.6.0",
4
4
  "description": "Docker production management CLI + MCP server for Claude Code",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -14,7 +14,7 @@
14
14
  "README.md"
15
15
  ],
16
16
  "scripts": {
17
- "build": "tsc",
17
+ "build": "tsc && tsc-alias",
18
18
  "dev": "tsx src/index.ts",
19
19
  "test": "vitest run",
20
20
  "prepublishOnly": "npm run build"
@@ -47,18 +47,46 @@
47
47
  "node": ">=20"
48
48
  },
49
49
  "dependencies": {
50
- "@modelcontextprotocol/sdk": "1.8.0",
50
+ "@matthesketh/ink-breadcrumb": "^0.1.0",
51
+ "@matthesketh/ink-chart": "0.1.0",
52
+ "@matthesketh/ink-form": "0.1.0",
53
+ "@matthesketh/ink-fuzzy-select": "0.1.0",
54
+ "@matthesketh/ink-gauge": "^0.1.0",
55
+ "@matthesketh/ink-input-dispatcher": "^0.1.0",
56
+ "@matthesketh/ink-keybinding-help": "^0.1.0",
57
+ "@matthesketh/ink-log-viewer": "^0.1.0",
58
+ "@matthesketh/ink-modal": "^0.1.0",
59
+ "@matthesketh/ink-pipeline": "^0.1.0",
60
+ "@matthesketh/ink-rule": "^0.1.0",
61
+ "@matthesketh/ink-scrollable-list": "^0.1.1",
62
+ "@matthesketh/ink-split-pane": "^0.1.0",
63
+ "@matthesketh/ink-stable-state": "^0.1.0",
64
+ "@matthesketh/ink-status-bar": "^0.1.0",
65
+ "@matthesketh/ink-table": "^0.1.0",
66
+ "@matthesketh/ink-tabs": "^0.1.0",
67
+ "@matthesketh/ink-task-list": "0.1.0",
68
+ "@matthesketh/ink-timeline": "0.1.0",
69
+ "@matthesketh/ink-toast": "^0.1.0",
70
+ "@matthesketh/ink-viewport": "^0.1.0",
71
+ "@modelcontextprotocol/sdk": "1.29.0",
72
+ "better-sqlite3": "12.9.0",
73
+ "chokidar": "5.0.0",
51
74
  "ink": "^5.2.1",
52
75
  "ink-spinner": "^5.0.0",
53
76
  "ink-text-input": "^6.0.0",
77
+ "proper-lockfile": "4.1.2",
54
78
  "react": "^18.3.1",
55
79
  "zod": "^3.24.0"
56
80
  },
57
81
  "devDependencies": {
82
+ "@types/better-sqlite3": "7.6.13",
58
83
  "@types/node": "20.17.0",
84
+ "@types/proper-lockfile": "4.1.4",
59
85
  "@types/react": "^18.3.28",
60
- "tsx": "4.19.2",
86
+ "ink-testing-library": "^4.0.0",
87
+ "tsc-alias": "1.8.16",
88
+ "tsx": "4.21.0",
61
89
  "typescript": "5.6.3",
62
90
  "vitest": "4.0.18"
63
91
  }
64
- }
92
+ }
@@ -1 +0,0 @@
1
- export declare function motdInstallCommand(): void;
@@ -1,10 +0,0 @@
1
- import { writeFileSync, chmodSync } from 'node:fs';
2
- import { generateMotdScript } from '../templates/motd.js';
3
- import { success } from '../ui/output.js';
4
- const MOTD_PATH = '/etc/update-motd.d/50-fleet-status';
5
- export function motdInstallCommand() {
6
- const script = generateMotdScript();
7
- writeFileSync(MOTD_PATH, script);
8
- chmodSync(MOTD_PATH, 0o755);
9
- success(`Installed MOTD script at ${MOTD_PATH}`);
10
- }
@@ -1 +0,0 @@
1
- export declare function generateMotdScript(): string;
@@ -1,7 +0,0 @@
1
- export function generateMotdScript() {
2
- return `#!/bin/bash
3
- # Fleet service health check — installed by "fleet motd install"
4
- # Shows service status on SSH login
5
- /usr/bin/node /home/matt/fleet/dist/index.js watchdog --motd 2>/dev/null || echo " Fleet: health check failed to run"
6
- `;
7
- }
@@ -1,12 +0,0 @@
1
- import React from 'react';
2
- interface AppListItem {
3
- name: string;
4
- label?: string;
5
- }
6
- interface AppListProps {
7
- items: AppListItem[];
8
- onSelect: (item: AppListItem) => void;
9
- renderItem?: (item: AppListItem, selected: boolean) => React.JSX.Element;
10
- }
11
- export declare function AppList({ items, onSelect, renderItem }: AppListProps): React.JSX.Element;
12
- export {};
@@ -1,32 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState } from 'react';
3
- import { Box, Text, useInput } from 'ink';
4
- import { colors } from '../theme.js';
5
- export function AppList({ items, onSelect, renderItem }) {
6
- const [selectedIndex, setSelectedIndex] = useState(0);
7
- useInput((input, key) => {
8
- if (items.length === 0)
9
- return;
10
- if (input === 'j' || key.downArrow) {
11
- setSelectedIndex(prev => Math.min(prev + 1, items.length - 1));
12
- }
13
- else if (input === 'k' || key.upArrow) {
14
- setSelectedIndex(prev => Math.max(prev - 1, 0));
15
- }
16
- else if (key.return) {
17
- if (items[selectedIndex]) {
18
- onSelect(items[selectedIndex]);
19
- }
20
- }
21
- });
22
- if (items.length === 0) {
23
- return _jsx(Text, { color: colors.muted, children: "No items" });
24
- }
25
- return (_jsx(Box, { flexDirection: "column", children: items.map((item, i) => {
26
- const selected = i === selectedIndex;
27
- if (renderItem) {
28
- return (_jsxs(Box, { children: [_jsx(Text, { color: colors.primary, children: selected ? '> ' : ' ' }), renderItem(item, selected)] }, item.name));
29
- }
30
- return (_jsxs(Text, { bold: selected, color: selected ? colors.primary : colors.text, children: [selected ? '> ' : ' ', item.label ?? item.name] }, item.name));
31
- }) }));
32
- }
@@ -1 +0,0 @@
1
- export declare function useKeyboard(): void;
@@ -1,44 +0,0 @@
1
- import { useInput } from 'ink';
2
- import { useAppState, useAppDispatch, nextTopView } from '../state.js';
3
- export function useKeyboard() {
4
- const state = useAppState();
5
- const dispatch = useAppDispatch();
6
- useInput((input, key) => {
7
- // Confirm dialog takes priority
8
- if (state.confirmAction) {
9
- if (input === 'y' || input === 'Y') {
10
- state.confirmAction.onConfirm();
11
- dispatch({ type: 'CANCEL_CONFIRM' });
12
- }
13
- else if (input === 'n' || input === 'N' || key.escape) {
14
- dispatch({ type: 'CANCEL_CONFIRM' });
15
- }
16
- return;
17
- }
18
- // Redact toggle (not in text-input views)
19
- if (input === 'x' && state.currentView !== 'secret-edit') {
20
- dispatch({ type: 'TOGGLE_REDACT' });
21
- return;
22
- }
23
- // Quit
24
- if (input === 'q') {
25
- process.exit(0);
26
- }
27
- // Tab cycles top-level views (only from top-level views)
28
- if (key.tab) {
29
- const topViews = ['dashboard', 'health', 'secrets'];
30
- const base = topViews.includes(state.currentView)
31
- ? state.currentView
32
- : state.previousView ?? 'dashboard';
33
- dispatch({ type: 'NAVIGATE', view: nextTopView(base) });
34
- return;
35
- }
36
- // Escape goes back
37
- if (key.escape) {
38
- if (state.previousView) {
39
- dispatch({ type: 'GO_BACK' });
40
- }
41
- return;
42
- }
43
- });
44
- }