crewly 1.20.303 → 1.20.305
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.
- package/config/skills/orchestrator/move-team/SKILL.md +53 -0
- package/config/skills/orchestrator/move-team/execute.sh +42 -0
- package/dist/backend/backend/src/constants.d.ts +82 -0
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +82 -0
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/team-move/team-move.controller.d.ts +39 -0
- package/dist/backend/backend/src/controllers/team-move/team-move.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/team-move/team-move.controller.js +211 -0
- package/dist/backend/backend/src/controllers/team-move/team-move.controller.js.map +1 -0
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +22 -3
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.js +3 -0
- package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-sync.types.d.ts +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-sync.types.d.ts.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-sync.types.js +1 -0
- package/dist/backend/backend/src/services/cloud/cloud-sync.types.js.map +1 -1
- package/dist/backend/backend/src/services/core/storage.service.d.ts +18 -0
- package/dist/backend/backend/src/services/core/storage.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/core/storage.service.js +16 -0
- package/dist/backend/backend/src/services/core/storage.service.js.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision.service.d.ts +19 -0
- package/dist/backend/backend/src/services/decisions/decision.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision.service.js +46 -0
- package/dist/backend/backend/src/services/decisions/decision.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-initializer.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-initializer.js +2 -1
- package/dist/backend/backend/src/services/slack/slack-initializer.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.d.ts +9 -0
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.js +25 -0
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
- package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts +19 -0
- package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/task-pool/task-pool.service.js +41 -0
- package/dist/backend/backend/src/services/task-pool/task-pool.service.js.map +1 -1
- package/dist/backend/backend/src/services/team-move/team-move-archive.d.ts +122 -0
- package/dist/backend/backend/src/services/team-move/team-move-archive.d.ts.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-archive.js +202 -0
- package/dist/backend/backend/src/services/team-move/team-move-archive.js.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-chat.d.ts +59 -0
- package/dist/backend/backend/src/services/team-move/team-move-chat.d.ts.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-chat.js +133 -0
- package/dist/backend/backend/src/services/team-move/team-move-chat.js.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-cloud.client.d.ts +102 -0
- package/dist/backend/backend/src/services/team-move/team-move-cloud.client.d.ts.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-cloud.client.js +217 -0
- package/dist/backend/backend/src/services/team-move/team-move-cloud.client.js.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-crypto.d.ts +102 -0
- package/dist/backend/backend/src/services/team-move/team-move-crypto.d.ts.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-crypto.js +348 -0
- package/dist/backend/backend/src/services/team-move/team-move-crypto.js.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-driver.service.d.ts +209 -0
- package/dist/backend/backend/src/services/team-move/team-move-driver.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-driver.service.js +504 -0
- package/dist/backend/backend/src/services/team-move/team-move-driver.service.js.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-exporter.d.ts +182 -0
- package/dist/backend/backend/src/services/team-move/team-move-exporter.d.ts.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-exporter.js +537 -0
- package/dist/backend/backend/src/services/team-move/team-move-exporter.js.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-fs.d.ts +157 -0
- package/dist/backend/backend/src/services/team-move/team-move-fs.d.ts.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-fs.js +298 -0
- package/dist/backend/backend/src/services/team-move/team-move-fs.js.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-git.d.ts +69 -0
- package/dist/backend/backend/src/services/team-move/team-move-git.d.ts.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-git.js +198 -0
- package/dist/backend/backend/src/services/team-move/team-move-git.js.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-importer.d.ts +121 -0
- package/dist/backend/backend/src/services/team-move/team-move-importer.d.ts.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-importer.js +473 -0
- package/dist/backend/backend/src/services/team-move/team-move-importer.js.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-journal.d.ts +110 -0
- package/dist/backend/backend/src/services/team-move/team-move-journal.d.ts.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-journal.js +198 -0
- package/dist/backend/backend/src/services/team-move/team-move-journal.js.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-machines.d.ts +62 -0
- package/dist/backend/backend/src/services/team-move/team-move-machines.d.ts.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-machines.js +95 -0
- package/dist/backend/backend/src/services/team-move/team-move-machines.js.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-preflight.d.ts +71 -0
- package/dist/backend/backend/src/services/team-move/team-move-preflight.d.ts.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-preflight.js +102 -0
- package/dist/backend/backend/src/services/team-move/team-move-preflight.js.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-runtime.d.ts +29 -0
- package/dist/backend/backend/src/services/team-move/team-move-runtime.d.ts.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-runtime.js +173 -0
- package/dist/backend/backend/src/services/team-move/team-move-runtime.js.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-secret-scan.d.ts +50 -0
- package/dist/backend/backend/src/services/team-move/team-move-secret-scan.d.ts.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-secret-scan.js +96 -0
- package/dist/backend/backend/src/services/team-move/team-move-secret-scan.js.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-select.d.ts +94 -0
- package/dist/backend/backend/src/services/team-move/team-move-select.d.ts.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move-select.js +124 -0
- package/dist/backend/backend/src/services/team-move/team-move-select.js.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move.fixture.d.ts +46 -0
- package/dist/backend/backend/src/services/team-move/team-move.fixture.d.ts.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move.fixture.js +202 -0
- package/dist/backend/backend/src/services/team-move/team-move.fixture.js.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move.types.d.ts +279 -0
- package/dist/backend/backend/src/services/team-move/team-move.types.d.ts.map +1 -0
- package/dist/backend/backend/src/services/team-move/team-move.types.js +44 -0
- package/dist/backend/backend/src/services/team-move/team-move.types.js.map +1 -0
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +82 -0
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +82 -0
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/cloud/cloud-sync.types.d.ts +1 -1
- package/dist/cli/backend/src/services/cloud/cloud-sync.types.d.ts.map +1 -1
- package/dist/cli/backend/src/services/cloud/cloud-sync.types.js +1 -0
- package/dist/cli/backend/src/services/cloud/cloud-sync.types.js.map +1 -1
- package/dist/cli/backend/src/services/core/storage.service.d.ts +18 -0
- package/dist/cli/backend/src/services/core/storage.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/core/storage.service.js +16 -0
- package/dist/cli/backend/src/services/core/storage.service.js.map +1 -1
- package/dist/cli/backend/src/services/decisions/decision.service.d.ts +19 -0
- package/dist/cli/backend/src/services/decisions/decision.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/decisions/decision.service.js +46 -0
- package/dist/cli/backend/src/services/decisions/decision.service.js.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.d.ts +9 -0
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.js +25 -0
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
- package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts +19 -0
- package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/task-pool/task-pool.service.js +41 -0
- package/dist/cli/backend/src/services/task-pool/task-pool.service.js.map +1 -1
- package/dist/cli/cli/src/commands/team-move.d.ts +68 -0
- package/dist/cli/cli/src/commands/team-move.d.ts.map +1 -0
- package/dist/cli/cli/src/commands/team-move.js +159 -0
- package/dist/cli/cli/src/commands/team-move.js.map +1 -0
- package/dist/cli/cli/src/index.js +33 -0
- package/dist/cli/cli/src/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Team move journal — resumable, idempotent steps.
|
|
3
|
+
*
|
|
4
|
+
* Every move keeps a directory `~/.crewly/team-moves/<moveId>/` with
|
|
5
|
+
* `journal.json` (which steps finished and what they produced) and
|
|
6
|
+
* `state.json` (what Cloud last asked for). A step that is recorded as done is
|
|
7
|
+
* skipped when the move is resumed after a crash or restart, and the step
|
|
8
|
+
* functions themselves are written so that running one twice is harmless.
|
|
9
|
+
*
|
|
10
|
+
* @module services/team-move/team-move-journal
|
|
11
|
+
*/
|
|
12
|
+
import * as fs from 'node:fs/promises';
|
|
13
|
+
import * as path from 'node:path';
|
|
14
|
+
import { TEAM_MOVE_CONSTANTS } from '../../constants.js';
|
|
15
|
+
import { atomicWriteJson, safeReadJson } from '../../utils/file-io.utils.js';
|
|
16
|
+
import { getCrewlyHomePath } from '../core/crewly-home.utils.js';
|
|
17
|
+
/** Move ids are Cloud-made; accept only path-safe ones. */
|
|
18
|
+
const MOVE_ID_PATTERN = /^[A-Za-z0-9_-]{8,64}$/;
|
|
19
|
+
/**
|
|
20
|
+
* Whether a string is a usable move id.
|
|
21
|
+
*
|
|
22
|
+
* @param value - Candidate
|
|
23
|
+
* @returns True for path-safe ids
|
|
24
|
+
*/
|
|
25
|
+
export function isMoveId(value) {
|
|
26
|
+
return typeof value === 'string' && MOVE_ID_PATTERN.test(value);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Directory of all moves on this machine.
|
|
30
|
+
*
|
|
31
|
+
* @param home - Crewly home (default: the process's)
|
|
32
|
+
* @returns Absolute path
|
|
33
|
+
*/
|
|
34
|
+
export function teamMovesRoot(home = getCrewlyHomePath()) {
|
|
35
|
+
return path.join(home, TEAM_MOVE_CONSTANTS.HOME_DIR);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Directory of one move.
|
|
39
|
+
*
|
|
40
|
+
* @param moveId - Move id
|
|
41
|
+
* @param home - Crewly home
|
|
42
|
+
* @returns Absolute path
|
|
43
|
+
* @throws Error for an id that is not path-safe
|
|
44
|
+
*/
|
|
45
|
+
export function moveDirFor(moveId, home = getCrewlyHomePath()) {
|
|
46
|
+
if (!isMoveId(moveId))
|
|
47
|
+
throw new Error('invalid move id');
|
|
48
|
+
return path.join(teamMovesRoot(home), moveId);
|
|
49
|
+
}
|
|
50
|
+
/** Journal and state of one move. */
|
|
51
|
+
export class MoveJournal {
|
|
52
|
+
moveId;
|
|
53
|
+
dir;
|
|
54
|
+
journalFile;
|
|
55
|
+
stateFile;
|
|
56
|
+
entries = null;
|
|
57
|
+
now;
|
|
58
|
+
/**
|
|
59
|
+
* @param moveId - Move id
|
|
60
|
+
* @param home - Crewly home
|
|
61
|
+
* @param now - Clock (tests)
|
|
62
|
+
*/
|
|
63
|
+
constructor(moveId, home = getCrewlyHomePath(), now = () => new Date().toISOString()) {
|
|
64
|
+
this.moveId = moveId;
|
|
65
|
+
this.dir = moveDirFor(moveId, home);
|
|
66
|
+
this.journalFile = path.join(this.dir, 'journal.json');
|
|
67
|
+
this.stateFile = path.join(this.dir, 'state.json');
|
|
68
|
+
this.now = now;
|
|
69
|
+
}
|
|
70
|
+
/** Create the move directory. */
|
|
71
|
+
async ensure() {
|
|
72
|
+
await fs.mkdir(this.dir, { recursive: true });
|
|
73
|
+
}
|
|
74
|
+
async load() {
|
|
75
|
+
if (!this.entries) {
|
|
76
|
+
const raw = await safeReadJson(this.journalFile, { entries: [] });
|
|
77
|
+
this.entries = Array.isArray(raw.entries) ? raw.entries : [];
|
|
78
|
+
}
|
|
79
|
+
return this.entries;
|
|
80
|
+
}
|
|
81
|
+
async append(entry) {
|
|
82
|
+
const entries = await this.load();
|
|
83
|
+
entries.push(entry);
|
|
84
|
+
await this.ensure();
|
|
85
|
+
await atomicWriteJson(this.journalFile, { entries });
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* All entries, oldest first.
|
|
89
|
+
*
|
|
90
|
+
* @returns Journal entries
|
|
91
|
+
*/
|
|
92
|
+
async list() {
|
|
93
|
+
return [...(await this.load())];
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Whether a step finished.
|
|
97
|
+
*
|
|
98
|
+
* @param step - Step name
|
|
99
|
+
* @returns True when its last entry is `done`
|
|
100
|
+
*/
|
|
101
|
+
async isDone(step) {
|
|
102
|
+
const entries = await this.load();
|
|
103
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
104
|
+
if (entries[i].step === step)
|
|
105
|
+
return entries[i].state === 'done';
|
|
106
|
+
}
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* What a finished step recorded.
|
|
111
|
+
*
|
|
112
|
+
* @param step - Step name
|
|
113
|
+
* @returns The `detail` of its last `done` entry, or undefined
|
|
114
|
+
*/
|
|
115
|
+
async detailOf(step) {
|
|
116
|
+
const entries = await this.load();
|
|
117
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
118
|
+
const e = entries[i];
|
|
119
|
+
if (e.step === step && e.state === 'done')
|
|
120
|
+
return e.detail;
|
|
121
|
+
}
|
|
122
|
+
return undefined;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Run a step once. A step already `done` is skipped and its recorded detail
|
|
126
|
+
* returned; a failure is recorded and rethrown.
|
|
127
|
+
*
|
|
128
|
+
* @param step - Step name
|
|
129
|
+
* @param fn - The step; its return value is stored as the step's detail
|
|
130
|
+
* @returns The step's detail (fresh or recorded)
|
|
131
|
+
*/
|
|
132
|
+
async run(step, fn) {
|
|
133
|
+
if (await this.isDone(step))
|
|
134
|
+
return (await this.detailOf(step));
|
|
135
|
+
await this.append({ step, state: 'started', at: this.now() });
|
|
136
|
+
try {
|
|
137
|
+
const detail = await fn();
|
|
138
|
+
await this.append({ step, state: 'done', at: this.now(), ...(detail === undefined ? {} : { detail }) });
|
|
139
|
+
return detail;
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
await this.append({ step, state: 'failed', at: this.now(), error: error instanceof Error ? error.message : String(error) });
|
|
143
|
+
throw error;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Forget a step so it runs again (e.g. a retry after the owner fixed something).
|
|
148
|
+
*
|
|
149
|
+
* @param step - Step name
|
|
150
|
+
*/
|
|
151
|
+
async reset(step) {
|
|
152
|
+
const entries = (await this.load()).filter((e) => e.step !== step);
|
|
153
|
+
this.entries = entries;
|
|
154
|
+
await this.ensure();
|
|
155
|
+
await atomicWriteJson(this.journalFile, { entries });
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Read `state.json`.
|
|
159
|
+
*
|
|
160
|
+
* @returns The state, or null before the first write
|
|
161
|
+
*/
|
|
162
|
+
async readState() {
|
|
163
|
+
return safeReadJson(this.stateFile, null);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Merge a patch into `state.json`.
|
|
167
|
+
*
|
|
168
|
+
* @param patch - Fields to set
|
|
169
|
+
* @returns The new state
|
|
170
|
+
*/
|
|
171
|
+
async writeState(patch) {
|
|
172
|
+
const current = await this.readState();
|
|
173
|
+
const next = {
|
|
174
|
+
moveId: this.moveId,
|
|
175
|
+
teamId: current?.teamId ?? patch.teamId ?? '',
|
|
176
|
+
teamName: current?.teamName ?? patch.teamName ?? '',
|
|
177
|
+
action: current?.action ?? null,
|
|
178
|
+
phase: current?.phase ?? 'idle',
|
|
179
|
+
...current,
|
|
180
|
+
...patch,
|
|
181
|
+
updatedAt: this.now(),
|
|
182
|
+
};
|
|
183
|
+
await this.ensure();
|
|
184
|
+
await atomicWriteJson(this.stateFile, next);
|
|
185
|
+
return next;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Ids of the moves that have a directory on this machine.
|
|
190
|
+
*
|
|
191
|
+
* @param home - Crewly home
|
|
192
|
+
* @returns Move ids
|
|
193
|
+
*/
|
|
194
|
+
export async function listLocalMoveIds(home = getCrewlyHomePath()) {
|
|
195
|
+
const entries = await fs.readdir(teamMovesRoot(home), { withFileTypes: true }).catch(() => []);
|
|
196
|
+
return entries.filter((e) => e.isDirectory() && isMoveId(e.name)).map((e) => e.name);
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=team-move-journal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"team-move-journal.js","sourceRoot":"","sources":["../../../../../../backend/src/services/team-move/team-move-journal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The machines a team can be moved to, from Crewly Cloud's instance registry
|
|
3
|
+
* (`GET /api/cloud/slack/instances`).
|
|
4
|
+
*
|
|
5
|
+
* The registry is noisy: it keeps stale and duplicate rows, nameless ids and
|
|
6
|
+
* virtual instances (the Cloud Slack bot). A machine is listed only when it
|
|
7
|
+
* heartbeated recently; rows are de-duplicated by name keeping the freshest;
|
|
8
|
+
* the local machine and virtual instances are left out. `canReceive` says
|
|
9
|
+
* whether the machine advertises the `teamMove:1` capability.
|
|
10
|
+
*
|
|
11
|
+
* @module services/team-move/team-move-machines
|
|
12
|
+
*/
|
|
13
|
+
import { type TeamMoveCloudSession } from './team-move-cloud.client.js';
|
|
14
|
+
/** An instance as Cloud lists it (the fields used here). */
|
|
15
|
+
export interface CloudInstanceRow {
|
|
16
|
+
instanceId?: string;
|
|
17
|
+
deviceName?: string;
|
|
18
|
+
crewlyVersion?: string;
|
|
19
|
+
capabilities?: string[];
|
|
20
|
+
lastSeenAt?: string;
|
|
21
|
+
}
|
|
22
|
+
/** A machine of the account. */
|
|
23
|
+
export interface MachineView {
|
|
24
|
+
instanceId: string;
|
|
25
|
+
name: string;
|
|
26
|
+
/** Always true for a listed machine: only recently seen machines are listed. */
|
|
27
|
+
online: boolean;
|
|
28
|
+
isLocal: boolean;
|
|
29
|
+
crewlyVersion?: string;
|
|
30
|
+
/** The machine advertises `teamMove:1`; otherwise Crewly has to be updated there. */
|
|
31
|
+
canReceive: boolean;
|
|
32
|
+
lastSeenAt?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Reduce Cloud's instance rows to the machines that matter.
|
|
36
|
+
*
|
|
37
|
+
* @param rows - Rows from the registry
|
|
38
|
+
* @param localInstanceId - This machine's instance id (excluded from the result)
|
|
39
|
+
* @param now - Current time (ms)
|
|
40
|
+
* @param liveWindowMs - Heartbeat age that still counts as online
|
|
41
|
+
* @returns Receivable and non-receivable remote machines, freshest first
|
|
42
|
+
*/
|
|
43
|
+
export declare function selectMachines(rows: readonly CloudInstanceRow[], localInstanceId: string | null, now: number, liveWindowMs?: number): MachineView[];
|
|
44
|
+
/**
|
|
45
|
+
* Owner-readable hints for machines that cannot take a team yet.
|
|
46
|
+
*
|
|
47
|
+
* @param machines - Machines from {@link selectMachines}
|
|
48
|
+
* @returns One line per machine that needs a Crewly update
|
|
49
|
+
*/
|
|
50
|
+
export declare function updateHints(machines: readonly MachineView[]): string[];
|
|
51
|
+
/**
|
|
52
|
+
* Read the account's live machines from Cloud.
|
|
53
|
+
*
|
|
54
|
+
* @param session - Cloud session (token and URL)
|
|
55
|
+
* @param localInstanceId - This machine's instance id
|
|
56
|
+
* @param fetchImpl - fetch (tests)
|
|
57
|
+
* @param now - Current time (ms)
|
|
58
|
+
* @returns Remote machines
|
|
59
|
+
* @throws TeamMoveCloudError when not signed in or Cloud refuses
|
|
60
|
+
*/
|
|
61
|
+
export declare function fetchMachines(session: TeamMoveCloudSession, localInstanceId: string | null, fetchImpl?: typeof fetch, now?: number): Promise<MachineView[]>;
|
|
62
|
+
//# sourceMappingURL=team-move-machines.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"team-move-machines.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/team-move/team-move-machines.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAsB,KAAK,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAI5F,4DAA4D;AAC5D,MAAM,WAAW,gBAAgB;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,gCAAgC;AAChC,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,gFAAgF;IAChF,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qFAAqF;IACrF,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,gBAAgB,EAAE,EAAE,eAAe,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,GAAE,MAAiC,GAAG,WAAW,EAAE,CA0B7K;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,GAAG,MAAM,EAAE,CAEtE;AAED;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,GAAG,IAAI,EAAE,SAAS,GAAE,OAAO,KAAa,EAAE,GAAG,GAAE,MAAmB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAiBpL"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The machines a team can be moved to, from Crewly Cloud's instance registry
|
|
3
|
+
* (`GET /api/cloud/slack/instances`).
|
|
4
|
+
*
|
|
5
|
+
* The registry is noisy: it keeps stale and duplicate rows, nameless ids and
|
|
6
|
+
* virtual instances (the Cloud Slack bot). A machine is listed only when it
|
|
7
|
+
* heartbeated recently; rows are de-duplicated by name keeping the freshest;
|
|
8
|
+
* the local machine and virtual instances are left out. `canReceive` says
|
|
9
|
+
* whether the machine advertises the `teamMove:1` capability.
|
|
10
|
+
*
|
|
11
|
+
* @module services/team-move/team-move-machines
|
|
12
|
+
*/
|
|
13
|
+
import { TEAM_MOVE_CONSTANTS } from '../../constants.js';
|
|
14
|
+
import { TeamMoveCloudError } from './team-move-cloud.client.js';
|
|
15
|
+
const C = TEAM_MOVE_CONSTANTS;
|
|
16
|
+
/**
|
|
17
|
+
* Reduce Cloud's instance rows to the machines that matter.
|
|
18
|
+
*
|
|
19
|
+
* @param rows - Rows from the registry
|
|
20
|
+
* @param localInstanceId - This machine's instance id (excluded from the result)
|
|
21
|
+
* @param now - Current time (ms)
|
|
22
|
+
* @param liveWindowMs - Heartbeat age that still counts as online
|
|
23
|
+
* @returns Receivable and non-receivable remote machines, freshest first
|
|
24
|
+
*/
|
|
25
|
+
export function selectMachines(rows, localInstanceId, now, liveWindowMs = C.MACHINE_LIVE_WINDOW_MS) {
|
|
26
|
+
const virtual = new RegExp(C.NON_MACHINE_INSTANCE_PATTERN, 'i');
|
|
27
|
+
const fresh = new Map();
|
|
28
|
+
for (const row of rows) {
|
|
29
|
+
const id = row.instanceId?.trim();
|
|
30
|
+
const name = row.deviceName?.trim();
|
|
31
|
+
if (!id || !name || virtual.test(id) || virtual.test(name))
|
|
32
|
+
continue;
|
|
33
|
+
const seen = row.lastSeenAt ? Date.parse(row.lastSeenAt) : NaN;
|
|
34
|
+
if (!Number.isFinite(seen) || now - seen > liveWindowMs)
|
|
35
|
+
continue;
|
|
36
|
+
// De-duplicate by name over all live rows (the local machine included), freshest wins.
|
|
37
|
+
const key = name.toLowerCase();
|
|
38
|
+
const current = fresh.get(key);
|
|
39
|
+
if (!current || seen > current.seen)
|
|
40
|
+
fresh.set(key, { row, seen });
|
|
41
|
+
}
|
|
42
|
+
return [...fresh.values()]
|
|
43
|
+
.filter(({ row }) => row.instanceId.trim() !== localInstanceId)
|
|
44
|
+
.sort((a, b) => b.seen - a.seen)
|
|
45
|
+
.map(({ row, seen }) => ({
|
|
46
|
+
instanceId: row.instanceId.trim(),
|
|
47
|
+
name: row.deviceName.trim(),
|
|
48
|
+
online: true,
|
|
49
|
+
isLocal: false,
|
|
50
|
+
...(row.crewlyVersion && row.crewlyVersion !== 'unknown' ? { crewlyVersion: row.crewlyVersion } : {}),
|
|
51
|
+
canReceive: Array.isArray(row.capabilities) && row.capabilities.includes(C.CAPABILITY),
|
|
52
|
+
lastSeenAt: new Date(seen).toISOString(),
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Owner-readable hints for machines that cannot take a team yet.
|
|
57
|
+
*
|
|
58
|
+
* @param machines - Machines from {@link selectMachines}
|
|
59
|
+
* @returns One line per machine that needs a Crewly update
|
|
60
|
+
*/
|
|
61
|
+
export function updateHints(machines) {
|
|
62
|
+
return machines.filter((m) => !m.canReceive).map((m) => `Update Crewly on ${m.name}${m.crewlyVersion ? ` (now ${m.crewlyVersion}, needs ${C.MIN_CREWLY_VERSION} or newer)` : ''} to move teams to it.`);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Read the account's live machines from Cloud.
|
|
66
|
+
*
|
|
67
|
+
* @param session - Cloud session (token and URL)
|
|
68
|
+
* @param localInstanceId - This machine's instance id
|
|
69
|
+
* @param fetchImpl - fetch (tests)
|
|
70
|
+
* @param now - Current time (ms)
|
|
71
|
+
* @returns Remote machines
|
|
72
|
+
* @throws TeamMoveCloudError when not signed in or Cloud refuses
|
|
73
|
+
*/
|
|
74
|
+
export async function fetchMachines(session, localInstanceId, fetchImpl = fetch, now = Date.now()) {
|
|
75
|
+
const token = session.getToken();
|
|
76
|
+
const base = session.getCloudUrl();
|
|
77
|
+
if (!token || !base)
|
|
78
|
+
throw new TeamMoveCloudError('Not signed in to Crewly Cloud', 401, 'not_logged_in');
|
|
79
|
+
let response;
|
|
80
|
+
try {
|
|
81
|
+
response = await fetchImpl(`${base.replace(/\/$/, '')}/api/cloud/slack/instances`, {
|
|
82
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
83
|
+
signal: AbortSignal.timeout(C.REQUEST_TIMEOUT_MS),
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
throw new TeamMoveCloudError(`Cloud unreachable: ${error instanceof Error ? error.message : String(error)}`, 0);
|
|
88
|
+
}
|
|
89
|
+
if (!response.ok)
|
|
90
|
+
throw new TeamMoveCloudError(`Cloud could not list machines (HTTP ${response.status})`, response.status);
|
|
91
|
+
const body = (await response.json().catch(() => ({})));
|
|
92
|
+
const rows = Array.isArray(body.data) ? body.data : [];
|
|
93
|
+
return selectMachines(rows, localInstanceId, now);
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=team-move-machines.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"team-move-machines.js","sourceRoot":"","sources":["../../../../../../backend/src/services/team-move/team-move-machines.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAA6B,MAAM,6BAA6B,CAAC;AAE5F,MAAM,CAAC,GAAG,mBAAmB,CAAC;AAwB9B;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,IAAiC,EAAE,eAA8B,EAAE,GAAW,EAAE,eAAuB,CAAC,CAAC,sBAAsB;IAC5J,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,CAAC,CAAC,4BAA4B,EAAE,GAAG,CAAC,CAAC;IAChE,MAAM,KAAK,GAAG,IAAI,GAAG,EAAmD,CAAC;IACzE,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,EAAE,GAAG,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC;QACpC,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,SAAS;QACrE,MAAM,IAAI,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QAC/D,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,GAAG,GAAG,IAAI,GAAG,YAAY;YAAE,SAAS;QAClE,uFAAuF;QACvF,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,CAAC,OAAO,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI;YAAE,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;SACvB,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,UAAW,CAAC,IAAI,EAAE,KAAK,eAAe,CAAC;SAC/D,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC;SAC/B,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QACvB,UAAU,EAAE,GAAG,CAAC,UAAW,CAAC,IAAI,EAAE;QAClC,IAAI,EAAE,GAAG,CAAC,UAAW,CAAC,IAAI,EAAE;QAC5B,MAAM,EAAE,IAAI;QACZ,OAAO,EAAE,KAAK;QACd,GAAG,CAAC,GAAG,CAAC,aAAa,IAAI,GAAG,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,GAAG,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrG,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC;QACtF,UAAU,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE;KACzC,CAAC,CAAC,CAAC;AACR,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,QAAgC;IAC1D,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,oBAAoB,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,aAAa,WAAW,CAAC,CAAC,kBAAkB,YAAY,CAAC,CAAC,CAAC,EAAE,uBAAuB,CAAC,CAAC;AAC1M,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAA6B,EAAE,eAA8B,EAAE,YAA0B,KAAK,EAAE,MAAc,IAAI,CAAC,GAAG,EAAE;IAC1J,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IACjC,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IACnC,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,kBAAkB,CAAC,+BAA+B,EAAE,GAAG,EAAE,eAAe,CAAC,CAAC;IACzG,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,SAAS,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,4BAA4B,EAAE;YACjF,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE;YAC7C,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC;SAClD,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,kBAAkB,CAAC,sBAAsB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IAClH,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,EAAE;QAAE,MAAM,IAAI,kBAAkB,CAAC,uCAAuC,QAAQ,CAAC,MAAM,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC3H,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAuB,CAAC;IAC7E,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAE,IAAI,CAAC,IAA2B,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/E,OAAO,cAAc,CAAC,IAAI,EAAE,eAAe,EAAE,GAAG,CAAC,CAAC;AACpD,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Target preflight: can this machine take a team? Reports its Crewly version,
|
|
3
|
+
* free disk space, the machine-only tools the team needs and which agent
|
|
4
|
+
* runtimes are logged in. Cloud shows the result to the owner and refuses a
|
|
5
|
+
* target that is too old or full.
|
|
6
|
+
*
|
|
7
|
+
* @module services/team-move/team-move-preflight
|
|
8
|
+
*/
|
|
9
|
+
import type { TeamMovePreflight } from './team-move.types.js';
|
|
10
|
+
/** Collaborators of the preflight (all injectable for tests). */
|
|
11
|
+
export interface PreflightDeps {
|
|
12
|
+
crewlyVersion: string;
|
|
13
|
+
/** Directory whose file system must hold the package (default: the home). */
|
|
14
|
+
diskPath: string;
|
|
15
|
+
/** Free bytes under `diskPath`; null when it cannot be read. */
|
|
16
|
+
freeDisk?: (dir: string) => Promise<number | null>;
|
|
17
|
+
/** Whether a command is on PATH. */
|
|
18
|
+
hasCommand?: (binary: string) => boolean;
|
|
19
|
+
/** Which runtimes are installed and logged in, by runtime id. */
|
|
20
|
+
runtimeLogins?: () => Promise<Record<string, boolean>>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Free bytes of the file system holding a directory.
|
|
24
|
+
*
|
|
25
|
+
* @param dir - Any path on it (the nearest existing parent is used)
|
|
26
|
+
* @returns Bytes available to this user, or null
|
|
27
|
+
*/
|
|
28
|
+
export declare function freeDiskBytes(dir: string): Promise<number | null>;
|
|
29
|
+
/**
|
|
30
|
+
* Whether a command is on PATH (including the directories Crewly adds for its
|
|
31
|
+
* harnesses and the usual Homebrew/Linux locations a launchd-started backend
|
|
32
|
+
* does not inherit).
|
|
33
|
+
*
|
|
34
|
+
* @param binary - Command name
|
|
35
|
+
* @returns True when found
|
|
36
|
+
*/
|
|
37
|
+
export declare function commandOnPath(binary: string): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Check which of a list of tools exist.
|
|
40
|
+
*
|
|
41
|
+
* @param tools - Tool names (keys of TEAM_MOVE_CONSTANTS.TOOL_BINARIES)
|
|
42
|
+
* @param hasCommand - PATH check
|
|
43
|
+
* @returns Tool name to present/absent
|
|
44
|
+
*/
|
|
45
|
+
export declare function checkTools(tools: readonly string[], hasCommand?: (binary: string) => boolean): Record<string, boolean>;
|
|
46
|
+
/**
|
|
47
|
+
* Preflight of this machine as the target of a move.
|
|
48
|
+
*
|
|
49
|
+
* @param deps - Version, disk path and probes
|
|
50
|
+
* @param requiredTools - Tools to check (the full known list when the package is not known yet)
|
|
51
|
+
* @returns What Cloud receives with the target's public key
|
|
52
|
+
*/
|
|
53
|
+
export declare function runPreflight(deps: PreflightDeps, requiredTools?: readonly string[]): Promise<TeamMovePreflight>;
|
|
54
|
+
/**
|
|
55
|
+
* Whether a version can take part in a move.
|
|
56
|
+
*
|
|
57
|
+
* @param version - Crewly version
|
|
58
|
+
* @returns True when at least {@link TEAM_MOVE_CONSTANTS.MIN_CREWLY_VERSION}
|
|
59
|
+
*/
|
|
60
|
+
export declare function isVersionCompatible(version: string): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Whether a disk can hold a package of the given size once it is downloaded
|
|
63
|
+
* and unpacked (ciphertext + unpacked copy + headroom).
|
|
64
|
+
*
|
|
65
|
+
* @param freeBytes - Free bytes
|
|
66
|
+
* @param packageBytes - Ciphertext size
|
|
67
|
+
* @param unpackedBytes - Uncompressed size from the manifest
|
|
68
|
+
* @returns True when there is room
|
|
69
|
+
*/
|
|
70
|
+
export declare function hasRoomFor(freeBytes: number, packageBytes: number, unpackedBytes: number): boolean;
|
|
71
|
+
//# sourceMappingURL=team-move-preflight.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"team-move-preflight.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/team-move/team-move-preflight.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,iEAAiE;AACjE,MAAM,WAAW,aAAa;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACnD,oCAAoC;IACpC,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;IACzC,iEAAiE;IACjE,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACxD;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAavE;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAIrD;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,UAAU,GAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAuB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAKrI;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,aAAa,EAAE,aAAa,GAAE,SAAS,MAAM,EAAoC,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAStJ;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAElG"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Target preflight: can this machine take a team? Reports its Crewly version,
|
|
3
|
+
* free disk space, the machine-only tools the team needs and which agent
|
|
4
|
+
* runtimes are logged in. Cloud shows the result to the owner and refuses a
|
|
5
|
+
* target that is too old or full.
|
|
6
|
+
*
|
|
7
|
+
* @module services/team-move/team-move-preflight
|
|
8
|
+
*/
|
|
9
|
+
import * as fs from 'node:fs/promises';
|
|
10
|
+
import * as os from 'node:os';
|
|
11
|
+
import * as path from 'node:path';
|
|
12
|
+
import { TEAM_MOVE_CONSTANTS } from '../../constants.js';
|
|
13
|
+
import { buildHarnessPath, resolveExecutable } from '../harness/harness-exec.utils.js';
|
|
14
|
+
import { compareVersions } from '../harness/harness-status.service.js';
|
|
15
|
+
/**
|
|
16
|
+
* Free bytes of the file system holding a directory.
|
|
17
|
+
*
|
|
18
|
+
* @param dir - Any path on it (the nearest existing parent is used)
|
|
19
|
+
* @returns Bytes available to this user, or null
|
|
20
|
+
*/
|
|
21
|
+
export async function freeDiskBytes(dir) {
|
|
22
|
+
let probe = dir;
|
|
23
|
+
for (let i = 0; i < 10; i++) {
|
|
24
|
+
try {
|
|
25
|
+
const stat = await fs.statfs(probe);
|
|
26
|
+
return Number(stat.bavail) * Number(stat.bsize);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
const parent = path.dirname(probe);
|
|
30
|
+
if (parent === probe)
|
|
31
|
+
return null;
|
|
32
|
+
probe = parent;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Whether a command is on PATH (including the directories Crewly adds for its
|
|
39
|
+
* harnesses and the usual Homebrew/Linux locations a launchd-started backend
|
|
40
|
+
* does not inherit).
|
|
41
|
+
*
|
|
42
|
+
* @param binary - Command name
|
|
43
|
+
* @returns True when found
|
|
44
|
+
*/
|
|
45
|
+
export function commandOnPath(binary) {
|
|
46
|
+
const extra = ['/opt/homebrew/bin', '/usr/local/bin', '/usr/bin', '/bin', path.join(os.homedir(), '.local', 'bin')];
|
|
47
|
+
const searchPath = [buildHarnessPath(process.env['PATH']), ...extra].join(path.delimiter);
|
|
48
|
+
return resolveExecutable(binary, searchPath) !== null;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Check which of a list of tools exist.
|
|
52
|
+
*
|
|
53
|
+
* @param tools - Tool names (keys of TEAM_MOVE_CONSTANTS.TOOL_BINARIES)
|
|
54
|
+
* @param hasCommand - PATH check
|
|
55
|
+
* @returns Tool name to present/absent
|
|
56
|
+
*/
|
|
57
|
+
export function checkTools(tools, hasCommand = commandOnPath) {
|
|
58
|
+
const binaries = TEAM_MOVE_CONSTANTS.TOOL_BINARIES;
|
|
59
|
+
const out = {};
|
|
60
|
+
for (const tool of tools)
|
|
61
|
+
out[tool] = hasCommand(binaries[tool] ?? tool);
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Preflight of this machine as the target of a move.
|
|
66
|
+
*
|
|
67
|
+
* @param deps - Version, disk path and probes
|
|
68
|
+
* @param requiredTools - Tools to check (the full known list when the package is not known yet)
|
|
69
|
+
* @returns What Cloud receives with the target's public key
|
|
70
|
+
*/
|
|
71
|
+
export async function runPreflight(deps, requiredTools = TEAM_MOVE_CONSTANTS.KNOWN_TOOLS) {
|
|
72
|
+
const free = await (deps.freeDisk ?? freeDiskBytes)(deps.diskPath);
|
|
73
|
+
const runtimes = deps.runtimeLogins ? await deps.runtimeLogins().catch(() => ({})) : {};
|
|
74
|
+
return {
|
|
75
|
+
crewlyVersion: deps.crewlyVersion,
|
|
76
|
+
freeDiskBytes: free ?? 0,
|
|
77
|
+
tools: checkTools(requiredTools, deps.hasCommand),
|
|
78
|
+
runtimes,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Whether a version can take part in a move.
|
|
83
|
+
*
|
|
84
|
+
* @param version - Crewly version
|
|
85
|
+
* @returns True when at least {@link TEAM_MOVE_CONSTANTS.MIN_CREWLY_VERSION}
|
|
86
|
+
*/
|
|
87
|
+
export function isVersionCompatible(version) {
|
|
88
|
+
return /^\d+\.\d+\.\d+/.test(version) && compareVersions(version, TEAM_MOVE_CONSTANTS.MIN_CREWLY_VERSION) >= 0;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Whether a disk can hold a package of the given size once it is downloaded
|
|
92
|
+
* and unpacked (ciphertext + unpacked copy + headroom).
|
|
93
|
+
*
|
|
94
|
+
* @param freeBytes - Free bytes
|
|
95
|
+
* @param packageBytes - Ciphertext size
|
|
96
|
+
* @param unpackedBytes - Uncompressed size from the manifest
|
|
97
|
+
* @returns True when there is room
|
|
98
|
+
*/
|
|
99
|
+
export function hasRoomFor(freeBytes, packageBytes, unpackedBytes) {
|
|
100
|
+
return freeBytes >= packageBytes + unpackedBytes + TEAM_MOVE_CONSTANTS.DISK_HEADROOM_BYTES;
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=team-move-preflight.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"team-move-preflight.js","sourceRoot":"","sources":["../../../../../../backend/src/services/team-move/team-move-preflight.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composition of the team move for the running backend: builds the exporter,
|
|
3
|
+
* importer, archiver and driver from the backend's own singletons (storage,
|
|
4
|
+
* task pool, decision cards, Slack team channels, harness status, device
|
|
5
|
+
* identity) so a move changes the live stores through their services and not
|
|
6
|
+
* behind their back.
|
|
7
|
+
*
|
|
8
|
+
* Starting and stopping a team goes through this backend's own REST API with
|
|
9
|
+
* the internal Cloud credential: the owner approved the move in Cloud, and the
|
|
10
|
+
* regular start/stop routes do the tmux and status bookkeeping.
|
|
11
|
+
*
|
|
12
|
+
* @module services/team-move/team-move-runtime
|
|
13
|
+
*/
|
|
14
|
+
import type { StorageService } from '../core/storage.service.js';
|
|
15
|
+
import { TeamMoveDriver, type TeamMoveRelaySource } from './team-move-driver.service.js';
|
|
16
|
+
/** Inputs of the composition. */
|
|
17
|
+
export interface TeamMoveRuntimeInput {
|
|
18
|
+
storage: StorageService;
|
|
19
|
+
relay: TeamMoveRelaySource;
|
|
20
|
+
home?: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Build the driver for the running backend.
|
|
24
|
+
*
|
|
25
|
+
* @param input - Storage and the relay event source
|
|
26
|
+
* @returns The driver (not started)
|
|
27
|
+
*/
|
|
28
|
+
export declare function createTeamMoveDriver(input: TeamMoveRuntimeInput): TeamMoveDriver;
|
|
29
|
+
//# sourceMappingURL=team-move-runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"team-move-runtime.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/team-move/team-move-runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAWH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAUjE,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAKzF,iCAAiC;AACjC,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,cAAc,CAAC;IACxB,KAAK,EAAE,mBAAmB,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AA0CD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,oBAAoB,GAAG,cAAc,CAkGhF"}
|