@fenwave/agent 1.1.3 ā 1.1.5
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/cli-commands.js +0 -7
- package/package.json +1 -1
- package/scripts/release.sh +212 -0
- package/setup/setupWizard.js +9 -107
package/cli-commands.js
CHANGED
|
@@ -127,7 +127,6 @@ function setupCLICommands(program, startServerFunction) {
|
|
|
127
127
|
.action(async () => {
|
|
128
128
|
try {
|
|
129
129
|
const { loadDeviceCredential, isDeviceRegistered } = await import('./store/deviceCredentialStore.js');
|
|
130
|
-
const { hasNpmToken } = await import('./store/npmTokenStore.js');
|
|
131
130
|
|
|
132
131
|
console.log(chalk.bold('\nš Fenwave Agent Status\n'));
|
|
133
132
|
|
|
@@ -233,7 +232,6 @@ function setupCLICommands(program, startServerFunction) {
|
|
|
233
232
|
try {
|
|
234
233
|
const { getDeviceMetadata } = await import('./utils/deviceInfo.js');
|
|
235
234
|
const { saveDeviceCredential, isDeviceRegistered } = await import('./store/deviceCredentialStore.js');
|
|
236
|
-
const { saveNpmToken } = await import('./store/npmTokenStore.js');
|
|
237
235
|
|
|
238
236
|
// Check if already registered
|
|
239
237
|
if (isDeviceRegistered()) {
|
|
@@ -299,11 +297,6 @@ function setupCLICommands(program, startServerFunction) {
|
|
|
299
297
|
agentVersion: deviceMetadata.agentVersion,
|
|
300
298
|
});
|
|
301
299
|
|
|
302
|
-
// Save NPM token if provided
|
|
303
|
-
if (response.data.npmToken) {
|
|
304
|
-
saveNpmToken(response.data.npmToken);
|
|
305
|
-
}
|
|
306
|
-
|
|
307
300
|
spinner.succeed('Device registered successfully');
|
|
308
301
|
console.log(chalk.green('\nā
Registration Complete'));
|
|
309
302
|
console.log(chalk.gray(` Device ID: ${response.data.deviceId}`));
|
package/package.json
CHANGED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Fenwave Agent Release Script
|
|
4
|
+
# Usage: ./scripts/release.sh [patch|minor|major|x.x.x]
|
|
5
|
+
|
|
6
|
+
set -e
|
|
7
|
+
|
|
8
|
+
# Colors
|
|
9
|
+
RED='\033[0;31m'
|
|
10
|
+
GREEN='\033[0;32m'
|
|
11
|
+
YELLOW='\033[1;33m'
|
|
12
|
+
BLUE='\033[0;34m'
|
|
13
|
+
NC='\033[0m' # No Color
|
|
14
|
+
|
|
15
|
+
# Functions
|
|
16
|
+
log_info() { echo -e "${BLUE}ā¹ ${NC}$1"; }
|
|
17
|
+
log_success() { echo -e "${GREEN}ā ${NC}$1"; }
|
|
18
|
+
log_warning() { echo -e "${YELLOW}ā ${NC}$1"; }
|
|
19
|
+
log_error() { echo -e "${RED}ā ${NC}$1"; exit 1; }
|
|
20
|
+
|
|
21
|
+
# Check prerequisites
|
|
22
|
+
check_prerequisites() {
|
|
23
|
+
log_info "Checking prerequisites..."
|
|
24
|
+
|
|
25
|
+
command -v node >/dev/null 2>&1 || log_error "Node.js is required"
|
|
26
|
+
command -v npm >/dev/null 2>&1 || log_error "npm is required"
|
|
27
|
+
command -v gh >/dev/null 2>&1 || log_error "GitHub CLI (gh) is required"
|
|
28
|
+
command -v git >/dev/null 2>&1 || log_error "git is required"
|
|
29
|
+
|
|
30
|
+
# Check if logged into npm
|
|
31
|
+
npm whoami >/dev/null 2>&1 || log_error "Not logged into npm. Run 'npm login' first"
|
|
32
|
+
|
|
33
|
+
# Check if logged into GitHub CLI
|
|
34
|
+
gh auth status >/dev/null 2>&1 || log_error "Not logged into GitHub CLI. Run 'gh auth login' first"
|
|
35
|
+
|
|
36
|
+
# Check for uncommitted changes
|
|
37
|
+
if [[ -n $(git status --porcelain) ]]; then
|
|
38
|
+
log_error "Working directory has uncommitted changes. Commit or stash them first"
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
# Check we're on main branch
|
|
42
|
+
CURRENT_BRANCH=$(git branch --show-current)
|
|
43
|
+
if [[ "$CURRENT_BRANCH" != "main" ]]; then
|
|
44
|
+
log_warning "Not on main branch (currently on: $CURRENT_BRANCH)"
|
|
45
|
+
read -p "Continue anyway? (y/N) " -n 1 -r
|
|
46
|
+
echo
|
|
47
|
+
[[ ! $REPLY =~ ^[Yy]$ ]] && exit 1
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# Pull latest changes
|
|
51
|
+
log_info "Pulling latest changes..."
|
|
52
|
+
git pull origin "$CURRENT_BRANCH"
|
|
53
|
+
|
|
54
|
+
log_success "Prerequisites check passed"
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# Get version argument
|
|
58
|
+
get_version() {
|
|
59
|
+
VERSION_ARG=$1
|
|
60
|
+
CURRENT_VERSION=$(node -p "require('./package.json').version")
|
|
61
|
+
|
|
62
|
+
if [[ -z "$VERSION_ARG" ]]; then
|
|
63
|
+
echo "" >&2
|
|
64
|
+
echo "Current version: $CURRENT_VERSION" >&2
|
|
65
|
+
echo "" >&2
|
|
66
|
+
echo "Select version bump:" >&2
|
|
67
|
+
echo " 1) patch (x.x.X) - Bug fixes" >&2
|
|
68
|
+
echo " 2) minor (x.X.0) - New features" >&2
|
|
69
|
+
echo " 3) major (X.0.0) - Breaking changes" >&2
|
|
70
|
+
echo " 4) custom - Enter specific version" >&2
|
|
71
|
+
echo "" >&2
|
|
72
|
+
read -p "Choice [1-4]: " choice
|
|
73
|
+
|
|
74
|
+
case $choice in
|
|
75
|
+
1) VERSION_ARG="patch" ;;
|
|
76
|
+
2) VERSION_ARG="minor" ;;
|
|
77
|
+
3) VERSION_ARG="major" ;;
|
|
78
|
+
4) read -p "Enter version (e.g., 1.2.3): " VERSION_ARG ;;
|
|
79
|
+
*) log_error "Invalid choice" ;;
|
|
80
|
+
esac
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
echo "$VERSION_ARG"
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
# Bump version
|
|
87
|
+
bump_version() {
|
|
88
|
+
local VERSION_TYPE=$1
|
|
89
|
+
|
|
90
|
+
log_info "Bumping version ($VERSION_TYPE)..." >&2
|
|
91
|
+
|
|
92
|
+
if [[ "$VERSION_TYPE" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
93
|
+
# Specific version provided
|
|
94
|
+
npm version "$VERSION_TYPE" --no-git-tag-version >/dev/null
|
|
95
|
+
else
|
|
96
|
+
# patch, minor, or major
|
|
97
|
+
npm version "$VERSION_TYPE" --no-git-tag-version >/dev/null
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
NEW_VERSION=$(node -p "require('./package.json').version")
|
|
101
|
+
log_success "Version bumped to $NEW_VERSION" >&2
|
|
102
|
+
|
|
103
|
+
echo "$NEW_VERSION"
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
# Commit and tag
|
|
107
|
+
commit_and_tag() {
|
|
108
|
+
local VERSION=$1
|
|
109
|
+
|
|
110
|
+
log_info "Committing version bump..."
|
|
111
|
+
|
|
112
|
+
git add package.json package-lock.json 2>/dev/null || git add package.json
|
|
113
|
+
git commit -m "chore: release v$VERSION"
|
|
114
|
+
|
|
115
|
+
log_info "Creating git tag v$VERSION..."
|
|
116
|
+
git tag -a "v$VERSION" -m "Release v$VERSION"
|
|
117
|
+
|
|
118
|
+
log_success "Committed and tagged"
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
# Push to remote
|
|
122
|
+
push_to_remote() {
|
|
123
|
+
local VERSION=$1
|
|
124
|
+
|
|
125
|
+
log_info "Pushing to remote..."
|
|
126
|
+
|
|
127
|
+
git push origin "$(git branch --show-current)"
|
|
128
|
+
git push origin "v$VERSION"
|
|
129
|
+
|
|
130
|
+
log_success "Pushed to remote"
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
# Create GitHub release
|
|
134
|
+
create_github_release() {
|
|
135
|
+
local VERSION=$1
|
|
136
|
+
|
|
137
|
+
log_info "Creating GitHub release..."
|
|
138
|
+
|
|
139
|
+
# Get commits since last tag
|
|
140
|
+
LAST_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
|
|
141
|
+
|
|
142
|
+
if [[ -n "$LAST_TAG" ]]; then
|
|
143
|
+
CHANGES=$(git log "$LAST_TAG"..HEAD --pretty=format:"- %s" --no-merges | grep -v "chore: release")
|
|
144
|
+
else
|
|
145
|
+
CHANGES="- Initial release"
|
|
146
|
+
fi
|
|
147
|
+
|
|
148
|
+
# Create release notes
|
|
149
|
+
RELEASE_NOTES="## What's Changed
|
|
150
|
+
|
|
151
|
+
$CHANGES
|
|
152
|
+
|
|
153
|
+
**Full Changelog**: https://github.com/$(gh repo view --json nameWithOwner -q .nameWithOwner)/compare/${LAST_TAG:-v0.0.0}...v$VERSION"
|
|
154
|
+
|
|
155
|
+
gh release create "v$VERSION" \
|
|
156
|
+
--title "v$VERSION" \
|
|
157
|
+
--notes "$RELEASE_NOTES"
|
|
158
|
+
|
|
159
|
+
log_success "GitHub release created"
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
# Publish to npm
|
|
163
|
+
publish_to_npm() {
|
|
164
|
+
log_info "Publishing to npm..."
|
|
165
|
+
|
|
166
|
+
# Check if OTP is needed
|
|
167
|
+
read -p "Enter npm OTP (leave empty if not using 2FA): " OTP
|
|
168
|
+
|
|
169
|
+
if [[ -n "$OTP" ]]; then
|
|
170
|
+
npm publish --access public --otp="$OTP"
|
|
171
|
+
else
|
|
172
|
+
npm publish --access public
|
|
173
|
+
fi
|
|
174
|
+
|
|
175
|
+
log_success "Published to npm"
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
# Main
|
|
179
|
+
main() {
|
|
180
|
+
echo ""
|
|
181
|
+
echo "āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā"
|
|
182
|
+
echo " Fenwave Agent Release Script"
|
|
183
|
+
echo "āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā"
|
|
184
|
+
echo ""
|
|
185
|
+
|
|
186
|
+
check_prerequisites
|
|
187
|
+
|
|
188
|
+
VERSION_ARG=$(get_version "$1")
|
|
189
|
+
NEW_VERSION=$(bump_version "$VERSION_ARG")
|
|
190
|
+
|
|
191
|
+
echo ""
|
|
192
|
+
log_info "Ready to release v$NEW_VERSION"
|
|
193
|
+
read -p "Continue with release? (y/N) " -n 1 -r
|
|
194
|
+
echo ""
|
|
195
|
+
[[ ! $REPLY =~ ^[Yy]$ ]] && { log_warning "Release cancelled"; exit 0; }
|
|
196
|
+
|
|
197
|
+
commit_and_tag "$NEW_VERSION"
|
|
198
|
+
push_to_remote "$NEW_VERSION"
|
|
199
|
+
create_github_release "$NEW_VERSION"
|
|
200
|
+
publish_to_npm
|
|
201
|
+
|
|
202
|
+
echo ""
|
|
203
|
+
echo "āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā"
|
|
204
|
+
echo -e "${GREEN} Release v$NEW_VERSION completed successfully!${NC}"
|
|
205
|
+
echo "āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā"
|
|
206
|
+
echo ""
|
|
207
|
+
echo " npm: https://www.npmjs.com/package/@fenwave/agent"
|
|
208
|
+
echo " GitHub: $(gh repo view --json url -q .url)/releases/tag/v$NEW_VERSION"
|
|
209
|
+
echo ""
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
main "$@"
|
package/setup/setupWizard.js
CHANGED
|
@@ -29,17 +29,15 @@ import {
|
|
|
29
29
|
saveDeviceCredential,
|
|
30
30
|
isDeviceRegistered,
|
|
31
31
|
} from "../store/deviceCredentialStore.js";
|
|
32
|
-
import { saveNpmToken } from "../store/npmTokenStore.js";
|
|
33
32
|
import {
|
|
34
33
|
saveSetupProgress,
|
|
35
34
|
clearSetupState,
|
|
36
35
|
SetupStep,
|
|
37
36
|
isSetupInProgress,
|
|
38
37
|
} from "../store/setupState.js";
|
|
39
|
-
import { authenticateDockerWithECR } from "../utils/ecrAuth.js";
|
|
40
38
|
import { initializeConfig } from "../store/configStore.js";
|
|
41
39
|
|
|
42
|
-
const TOTAL_STEPS =
|
|
40
|
+
const TOTAL_STEPS = 5; // Reduced - no ECR auth or NPM config needed (public package and GHCR)
|
|
43
41
|
|
|
44
42
|
/**
|
|
45
43
|
* Setup Wizard Orchestrator
|
|
@@ -49,8 +47,6 @@ export class SetupWizard {
|
|
|
49
47
|
constructor(options = {}) {
|
|
50
48
|
this.backendUrl = options.backendUrl || "http://localhost:7007";
|
|
51
49
|
this.frontendUrl = options.frontendUrl || "http://localhost:3000";
|
|
52
|
-
this.awsRegion = options.awsRegion || "eu-west-1";
|
|
53
|
-
this.awsAccountId = options.awsAccountId || null; // Will be set from Backstage during registration
|
|
54
50
|
this.skipPrerequisites = options.skipPrerequisites || false;
|
|
55
51
|
this.registrationToken = options.token || null;
|
|
56
52
|
}
|
|
@@ -67,8 +63,6 @@ export class SetupWizard {
|
|
|
67
63
|
const agentConfig = {
|
|
68
64
|
backendUrl: this.backendUrl,
|
|
69
65
|
frontendUrl: this.frontendUrl,
|
|
70
|
-
awsRegion: this.awsRegion,
|
|
71
|
-
awsAccountId: this.awsAccountId,
|
|
72
66
|
};
|
|
73
67
|
|
|
74
68
|
initializeConfig(agentConfig);
|
|
@@ -76,10 +70,6 @@ export class SetupWizard {
|
|
|
76
70
|
displayInfo("Agent configuration initialized:");
|
|
77
71
|
displayKeyValue("Backend URL", this.backendUrl);
|
|
78
72
|
displayKeyValue("Frontend URL", this.frontendUrl);
|
|
79
|
-
displayKeyValue("AWS Region", this.awsRegion);
|
|
80
|
-
if (this.awsAccountId) {
|
|
81
|
-
displayKeyValue("AWS Account ID", this.awsAccountId);
|
|
82
|
-
}
|
|
83
73
|
console.log("");
|
|
84
74
|
|
|
85
75
|
// Check if already registered
|
|
@@ -116,19 +106,13 @@ export class SetupWizard {
|
|
|
116
106
|
// Step 2: Device Registration
|
|
117
107
|
const registrationData = await this.registrationStep();
|
|
118
108
|
|
|
119
|
-
// Step 3:
|
|
120
|
-
await this.dockerRegistryStep(registrationData);
|
|
121
|
-
|
|
122
|
-
// Step 4: Pull DevApp Image
|
|
109
|
+
// Step 3: Pull DevApp Image (GHCR is public, no auth required)
|
|
123
110
|
await this.pullImageStep(registrationData);
|
|
124
111
|
|
|
125
|
-
// Step
|
|
126
|
-
await this.npmConfigStep(registrationData);
|
|
127
|
-
|
|
128
|
-
// Step 6: Start Agent (optional)
|
|
112
|
+
// Step 4: Start Agent (optional)
|
|
129
113
|
await this.startAgentStep();
|
|
130
114
|
|
|
131
|
-
// Step
|
|
115
|
+
// Step 5: Complete
|
|
132
116
|
this.displayComplete(registrationData);
|
|
133
117
|
|
|
134
118
|
// Clear setup state
|
|
@@ -266,7 +250,6 @@ export class SetupWizard {
|
|
|
266
250
|
return {
|
|
267
251
|
deviceId: response.data.deviceId,
|
|
268
252
|
deviceCredential: response.data.deviceCredential,
|
|
269
|
-
npmToken: response.data.npmToken,
|
|
270
253
|
registryConfig: response.data.registryConfig,
|
|
271
254
|
userEntityRef: response.data.userEntityRef || "unknown",
|
|
272
255
|
};
|
|
@@ -288,73 +271,10 @@ export class SetupWizard {
|
|
|
288
271
|
}
|
|
289
272
|
|
|
290
273
|
/**
|
|
291
|
-
* Step 3:
|
|
292
|
-
*/
|
|
293
|
-
async dockerRegistryStep(registrationData) {
|
|
294
|
-
displayStep(3, TOTAL_STEPS, "Docker Registry Configuration");
|
|
295
|
-
|
|
296
|
-
const shouldConfigure = await promptConfirmation(
|
|
297
|
-
"Configure AWS ECR for Fenwave images?",
|
|
298
|
-
true
|
|
299
|
-
);
|
|
300
|
-
|
|
301
|
-
if (!shouldConfigure) {
|
|
302
|
-
displayInfo("Skipping Docker registry configuration");
|
|
303
|
-
saveSetupProgress(SetupStep.DOCKER_REGISTRY, { skipped: true });
|
|
304
|
-
return;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
const { awsRegion, awsAccountId } = registrationData.registryConfig;
|
|
308
|
-
|
|
309
|
-
displayInfo(`Authenticating with AWS ECR (${awsRegion})...`);
|
|
310
|
-
displayInfo(
|
|
311
|
-
"š Using Backstage-controlled credential flow (temporary credentials)"
|
|
312
|
-
);
|
|
313
|
-
|
|
314
|
-
try {
|
|
315
|
-
// Use Backstage-controlled credential flow
|
|
316
|
-
const authResult = await authenticateDockerWithECR(this.backendUrl);
|
|
317
|
-
|
|
318
|
-
displaySuccess("AWS ECR authenticated successfully");
|
|
319
|
-
displayInfo(`ā
Credentials expire at: ${authResult.expiration}`);
|
|
320
|
-
displayInfo(`š¦ Registry: ${authResult.registryUri}`);
|
|
321
|
-
|
|
322
|
-
saveSetupProgress(SetupStep.DOCKER_REGISTRY, {
|
|
323
|
-
awsRegion: authResult.region,
|
|
324
|
-
awsAccountId: authResult.accountId,
|
|
325
|
-
registryUri: authResult.registryUri,
|
|
326
|
-
expiration: authResult.expiration,
|
|
327
|
-
});
|
|
328
|
-
} catch (error) {
|
|
329
|
-
displayError("Failed to authenticate with AWS ECR");
|
|
330
|
-
displayError(`Error: ${error.message}`);
|
|
331
|
-
displayWarning(
|
|
332
|
-
"Make sure your device is registered and Backstage is running"
|
|
333
|
-
);
|
|
334
|
-
|
|
335
|
-
const shouldContinue = await promptConfirmation(
|
|
336
|
-
"Continue without ECR authentication?",
|
|
337
|
-
true
|
|
338
|
-
);
|
|
339
|
-
if (!shouldContinue) {
|
|
340
|
-
throw createError(
|
|
341
|
-
ErrorCode.ECR_AUTH_FAILED,
|
|
342
|
-
"ECR authentication failed"
|
|
343
|
-
);
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
saveSetupProgress(SetupStep.DOCKER_REGISTRY, {
|
|
347
|
-
failed: true,
|
|
348
|
-
error: error.message,
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
/**
|
|
354
|
-
* Step 4: Pull Fenwave DevApp Image
|
|
274
|
+
* Step 3: Pull Fenwave DevApp Image (GHCR is public, no auth required)
|
|
355
275
|
*/
|
|
356
276
|
async pullImageStep(registrationData) {
|
|
357
|
-
displayStep(
|
|
277
|
+
displayStep(3, TOTAL_STEPS, "Pull Fenwave DevApp Image");
|
|
358
278
|
|
|
359
279
|
const shouldPull = await promptConfirmation(
|
|
360
280
|
"Pull Fenwave DevApp Docker image?",
|
|
@@ -412,28 +332,10 @@ export class SetupWizard {
|
|
|
412
332
|
}
|
|
413
333
|
|
|
414
334
|
/**
|
|
415
|
-
* Step
|
|
416
|
-
*/
|
|
417
|
-
async npmConfigStep(registrationData) {
|
|
418
|
-
displayStep(5, TOTAL_STEPS, "NPM Configuration");
|
|
419
|
-
|
|
420
|
-
const { npmToken } = registrationData;
|
|
421
|
-
|
|
422
|
-
if (npmToken) {
|
|
423
|
-
saveNpmToken(npmToken);
|
|
424
|
-
displaySuccess("NPM token configured for future updates");
|
|
425
|
-
saveSetupProgress(SetupStep.NPM_CONFIG, { configured: true });
|
|
426
|
-
} else {
|
|
427
|
-
displayWarning("No NPM token provided by backend");
|
|
428
|
-
saveSetupProgress(SetupStep.NPM_CONFIG, { configured: false });
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
/**
|
|
433
|
-
* Step 6: Start Agent (optional)
|
|
335
|
+
* Step 4: Start Agent (optional)
|
|
434
336
|
*/
|
|
435
337
|
async startAgentStep() {
|
|
436
|
-
displayStep(
|
|
338
|
+
displayStep(4, TOTAL_STEPS, "Start Agent Service");
|
|
437
339
|
|
|
438
340
|
const shouldStart = await promptConfirmation("Start the agent now?", true);
|
|
439
341
|
|
|
@@ -453,7 +355,7 @@ export class SetupWizard {
|
|
|
453
355
|
* Display completion message
|
|
454
356
|
*/
|
|
455
357
|
displayComplete(registrationData) {
|
|
456
|
-
displayStep(
|
|
358
|
+
displayStep(5, TOTAL_STEPS, "Setup Complete! š");
|
|
457
359
|
|
|
458
360
|
console.log("");
|
|
459
361
|
displayHeader("Setup Summary");
|