@bagdock/cli 0.2.0 → 0.4.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.
- package/README.md +724 -22
- package/dist/bagdock.js +857 -87
- package/package.json +14 -5
- package/skill-evals/bagdock-cli/evals.json +208 -0
- package/skills/bagdock-cli/SKILL.md +161 -0
- package/skills/bagdock-cli/references/app-management.md +63 -0
- package/skills/bagdock-cli/references/auth.md +113 -0
- package/skills/bagdock-cli/references/deploy.md +91 -0
- package/skills/bagdock-cli/references/dev.md +45 -0
- package/skills/bagdock-cli/references/env.md +37 -0
- package/skills/bagdock-cli/references/error-codes.md +53 -0
- package/skills/bagdock-cli/references/marketplace.md +69 -0
package/dist/bagdock.js
CHANGED
|
@@ -2085,31 +2085,87 @@ var require_commander = __commonJS((exports) => {
|
|
|
2085
2085
|
import { homedir } from "os";
|
|
2086
2086
|
import { join } from "path";
|
|
2087
2087
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
2088
|
+
function setProfileOverride(name) {
|
|
2089
|
+
profileOverride = name;
|
|
2090
|
+
}
|
|
2088
2091
|
function ensureConfigDir() {
|
|
2089
2092
|
if (!existsSync(CONFIG_DIR)) {
|
|
2090
2093
|
mkdirSync(CONFIG_DIR, { recursive: true, mode: 448 });
|
|
2091
2094
|
}
|
|
2092
2095
|
}
|
|
2093
|
-
function
|
|
2096
|
+
function loadStore() {
|
|
2094
2097
|
try {
|
|
2095
|
-
if (!existsSync(CREDENTIALS_FILE))
|
|
2096
|
-
return
|
|
2097
|
-
|
|
2098
|
-
|
|
2098
|
+
if (!existsSync(CREDENTIALS_FILE)) {
|
|
2099
|
+
return { activeProfile: "default", profiles: {} };
|
|
2100
|
+
}
|
|
2101
|
+
const raw = JSON.parse(readFileSync(CREDENTIALS_FILE, "utf-8"));
|
|
2102
|
+
if (raw.accessToken && !raw.profiles) {
|
|
2103
|
+
const migrated = {
|
|
2104
|
+
activeProfile: "default",
|
|
2105
|
+
profiles: { default: raw }
|
|
2106
|
+
};
|
|
2107
|
+
saveStore(migrated);
|
|
2108
|
+
return migrated;
|
|
2109
|
+
}
|
|
2110
|
+
return raw;
|
|
2099
2111
|
} catch {
|
|
2100
|
-
return
|
|
2112
|
+
return { activeProfile: "default", profiles: {} };
|
|
2101
2113
|
}
|
|
2102
2114
|
}
|
|
2103
|
-
function
|
|
2115
|
+
function saveStore(store) {
|
|
2104
2116
|
ensureConfigDir();
|
|
2105
|
-
writeFileSync(CREDENTIALS_FILE, JSON.stringify(
|
|
2117
|
+
writeFileSync(CREDENTIALS_FILE, JSON.stringify(store, null, 2), { mode: 384 });
|
|
2118
|
+
}
|
|
2119
|
+
function resolveProfile() {
|
|
2120
|
+
if (profileOverride)
|
|
2121
|
+
return profileOverride;
|
|
2122
|
+
if (process.env.BAGDOCK_PROFILE)
|
|
2123
|
+
return process.env.BAGDOCK_PROFILE;
|
|
2124
|
+
return loadStore().activeProfile;
|
|
2125
|
+
}
|
|
2126
|
+
function loadCredentials() {
|
|
2127
|
+
const store = loadStore();
|
|
2128
|
+
const name = resolveProfile();
|
|
2129
|
+
return store.profiles[name] ?? null;
|
|
2130
|
+
}
|
|
2131
|
+
function saveCredentials(creds, profileName) {
|
|
2132
|
+
const store = loadStore();
|
|
2133
|
+
const name = profileName ?? resolveProfile();
|
|
2134
|
+
store.profiles[name] = creds;
|
|
2135
|
+
if (!store.activeProfile || Object.keys(store.profiles).length === 1) {
|
|
2136
|
+
store.activeProfile = name;
|
|
2137
|
+
}
|
|
2138
|
+
saveStore(store);
|
|
2106
2139
|
}
|
|
2107
2140
|
function clearCredentials() {
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2141
|
+
const store = loadStore();
|
|
2142
|
+
const name = resolveProfile();
|
|
2143
|
+
delete store.profiles[name];
|
|
2144
|
+
if (store.activeProfile === name) {
|
|
2145
|
+
const remaining = Object.keys(store.profiles);
|
|
2146
|
+
store.activeProfile = remaining[0] ?? "default";
|
|
2147
|
+
}
|
|
2148
|
+
saveStore(store);
|
|
2149
|
+
}
|
|
2150
|
+
function listProfiles() {
|
|
2151
|
+
const store = loadStore();
|
|
2152
|
+
return Object.entries(store.profiles).map(([name, creds]) => ({
|
|
2153
|
+
name,
|
|
2154
|
+
email: creds.email,
|
|
2155
|
+
operatorId: creds.operatorId,
|
|
2156
|
+
active: name === store.activeProfile
|
|
2157
|
+
}));
|
|
2158
|
+
}
|
|
2159
|
+
function switchProfile(name) {
|
|
2160
|
+
const store = loadStore();
|
|
2161
|
+
if (!store.profiles[name])
|
|
2162
|
+
return false;
|
|
2163
|
+
store.activeProfile = name;
|
|
2164
|
+
saveStore(store);
|
|
2165
|
+
return true;
|
|
2166
|
+
}
|
|
2167
|
+
function getActiveProfileName() {
|
|
2168
|
+
return resolveProfile();
|
|
2113
2169
|
}
|
|
2114
2170
|
function loadBagdockJson(dir) {
|
|
2115
2171
|
const file = join(dir, "bagdock.json");
|
|
@@ -2121,7 +2177,7 @@ function loadBagdockJson(dir) {
|
|
|
2121
2177
|
return null;
|
|
2122
2178
|
}
|
|
2123
2179
|
}
|
|
2124
|
-
var CONFIG_DIR, CREDENTIALS_FILE, API_BASE, DASHBOARD_BASE;
|
|
2180
|
+
var CONFIG_DIR, CREDENTIALS_FILE, API_BASE, DASHBOARD_BASE, profileOverride;
|
|
2125
2181
|
var init_config = __esm(() => {
|
|
2126
2182
|
CONFIG_DIR = join(homedir(), ".bagdock");
|
|
2127
2183
|
CREDENTIALS_FILE = join(CONFIG_DIR, "credentials.json");
|
|
@@ -2618,6 +2674,59 @@ var init_source = __esm(() => {
|
|
|
2618
2674
|
source_default = chalk;
|
|
2619
2675
|
});
|
|
2620
2676
|
|
|
2677
|
+
// src/output.ts
|
|
2678
|
+
function setOutputMode(opts) {
|
|
2679
|
+
quiet = !!opts.quiet;
|
|
2680
|
+
forceJson = !!opts.json || !!opts.quiet;
|
|
2681
|
+
}
|
|
2682
|
+
function isJsonMode() {
|
|
2683
|
+
return forceJson || !process.stdout.isTTY;
|
|
2684
|
+
}
|
|
2685
|
+
function isQuiet() {
|
|
2686
|
+
return quiet;
|
|
2687
|
+
}
|
|
2688
|
+
function outputSuccess(data) {
|
|
2689
|
+
if (isJsonMode()) {
|
|
2690
|
+
process.stdout.write(JSON.stringify(data, null, 2) + `
|
|
2691
|
+
`);
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
function outputError(code, message, details) {
|
|
2695
|
+
if (isJsonMode()) {
|
|
2696
|
+
const err = { error: { code, message } };
|
|
2697
|
+
if (details)
|
|
2698
|
+
err.error.details = details;
|
|
2699
|
+
process.stderr.write(JSON.stringify(err) + `
|
|
2700
|
+
`);
|
|
2701
|
+
process.exit(1);
|
|
2702
|
+
} else {
|
|
2703
|
+
console.error(source_default.red(`Error [${code}]:`), message);
|
|
2704
|
+
if (details)
|
|
2705
|
+
console.error(details);
|
|
2706
|
+
process.exit(1);
|
|
2707
|
+
}
|
|
2708
|
+
}
|
|
2709
|
+
function outputList(objectType, data, hasMore) {
|
|
2710
|
+
if (isJsonMode()) {
|
|
2711
|
+
process.stdout.write(JSON.stringify({ object: "list", data, has_more: hasMore }, null, 2) + `
|
|
2712
|
+
`);
|
|
2713
|
+
}
|
|
2714
|
+
}
|
|
2715
|
+
function status(message) {
|
|
2716
|
+
if (!isQuiet() && !isJsonMode()) {
|
|
2717
|
+
console.log(source_default.dim(message));
|
|
2718
|
+
}
|
|
2719
|
+
}
|
|
2720
|
+
function success(message) {
|
|
2721
|
+
if (!isQuiet() && !isJsonMode()) {
|
|
2722
|
+
console.log(source_default.green(message));
|
|
2723
|
+
}
|
|
2724
|
+
}
|
|
2725
|
+
var forceJson = false, quiet = false;
|
|
2726
|
+
var init_output = __esm(() => {
|
|
2727
|
+
init_source();
|
|
2728
|
+
});
|
|
2729
|
+
|
|
2621
2730
|
// node_modules/is-docker/index.js
|
|
2622
2731
|
import fs from "node:fs";
|
|
2623
2732
|
function hasDockerEnv() {
|
|
@@ -3172,6 +3281,18 @@ function getAuthToken() {
|
|
|
3172
3281
|
const creds = loadCredentials();
|
|
3173
3282
|
return creds?.accessToken ?? null;
|
|
3174
3283
|
}
|
|
3284
|
+
function getAuthSource() {
|
|
3285
|
+
if (apiKeyOverride)
|
|
3286
|
+
return { token: apiKeyOverride, source: "flag" };
|
|
3287
|
+
if (process.env.BAGDOCK_API_KEY)
|
|
3288
|
+
return { token: process.env.BAGDOCK_API_KEY, source: "env (BAGDOCK_API_KEY)" };
|
|
3289
|
+
if (process.env.BAGDOCK_TOKEN)
|
|
3290
|
+
return { token: process.env.BAGDOCK_TOKEN, source: "env (BAGDOCK_TOKEN)" };
|
|
3291
|
+
const creds = loadCredentials();
|
|
3292
|
+
if (creds?.accessToken)
|
|
3293
|
+
return { token: creds.accessToken, source: `config (${getActiveProfileName()})` };
|
|
3294
|
+
return { token: null, source: "none" };
|
|
3295
|
+
}
|
|
3175
3296
|
async function login() {
|
|
3176
3297
|
const existing = loadCredentials();
|
|
3177
3298
|
if (existing?.accessToken && existing.expiresAt && existing.expiresAt > Date.now()) {
|
|
@@ -3228,12 +3349,12 @@ Requesting device authorization...
|
|
|
3228
3349
|
console.log(" Email:", source_default.bold(tokens.email));
|
|
3229
3350
|
if (tokens.operator_id)
|
|
3230
3351
|
console.log(" Operator:", source_default.bold(tokens.operator_id));
|
|
3352
|
+
console.log(" Profile:", source_default.bold(getActiveProfileName()));
|
|
3231
3353
|
return;
|
|
3232
3354
|
}
|
|
3233
3355
|
const error = await tokenRes.json().catch(() => ({ error: "unknown" }));
|
|
3234
|
-
if (error.error === "authorization_pending")
|
|
3356
|
+
if (error.error === "authorization_pending")
|
|
3235
3357
|
continue;
|
|
3236
|
-
}
|
|
3237
3358
|
if (error.error === "slow_down") {
|
|
3238
3359
|
await sleep(pollInterval);
|
|
3239
3360
|
continue;
|
|
@@ -3258,7 +3379,7 @@ Requesting device authorization...
|
|
|
3258
3379
|
}
|
|
3259
3380
|
async function logout() {
|
|
3260
3381
|
clearCredentials();
|
|
3261
|
-
console.log(source_default.green(
|
|
3382
|
+
console.log(source_default.green(`Logged out of profile "${getActiveProfileName()}".`));
|
|
3262
3383
|
}
|
|
3263
3384
|
async function whoami() {
|
|
3264
3385
|
const token = getAuthToken();
|
|
@@ -3275,16 +3396,92 @@ async function whoami() {
|
|
|
3275
3396
|
process.exit(1);
|
|
3276
3397
|
}
|
|
3277
3398
|
const user = await res.json();
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3399
|
+
if (isJsonMode()) {
|
|
3400
|
+
outputSuccess({ ...user, profile: getActiveProfileName() });
|
|
3401
|
+
} else {
|
|
3402
|
+
console.log(source_default.green("Logged in as"), source_default.bold(user.email));
|
|
3403
|
+
if (user.operator_id)
|
|
3404
|
+
console.log("Operator:", source_default.bold(user.operator_id));
|
|
3405
|
+
if (user.name)
|
|
3406
|
+
console.log("Name:", user.name);
|
|
3407
|
+
console.log("Profile:", source_default.bold(getActiveProfileName()));
|
|
3408
|
+
}
|
|
3283
3409
|
} catch (err) {
|
|
3284
3410
|
console.log(source_default.red("Failed to reach API:"), err.message);
|
|
3285
3411
|
process.exit(1);
|
|
3286
3412
|
}
|
|
3287
3413
|
}
|
|
3414
|
+
async function authList() {
|
|
3415
|
+
const profiles = listProfiles();
|
|
3416
|
+
if (isJsonMode()) {
|
|
3417
|
+
outputSuccess({ profiles });
|
|
3418
|
+
return;
|
|
3419
|
+
}
|
|
3420
|
+
if (!profiles.length) {
|
|
3421
|
+
console.log(source_default.yellow(`
|
|
3422
|
+
No profiles found.`), "Run", source_default.cyan("bagdock login"), `to create one.
|
|
3423
|
+
`);
|
|
3424
|
+
return;
|
|
3425
|
+
}
|
|
3426
|
+
console.log();
|
|
3427
|
+
for (const p of profiles) {
|
|
3428
|
+
const marker = p.active ? source_default.green("* ") : " ";
|
|
3429
|
+
const label = p.active ? source_default.bold(p.name) : p.name;
|
|
3430
|
+
const email = p.email ? source_default.dim(` (${p.email})`) : "";
|
|
3431
|
+
const op = p.operatorId ? source_default.dim(` [${p.operatorId}]`) : "";
|
|
3432
|
+
console.log(` ${marker}${label}${email}${op}`);
|
|
3433
|
+
}
|
|
3434
|
+
console.log();
|
|
3435
|
+
}
|
|
3436
|
+
async function authSwitch(name) {
|
|
3437
|
+
const profiles = listProfiles();
|
|
3438
|
+
if (!profiles.length) {
|
|
3439
|
+
console.log(source_default.yellow("No profiles found."), "Run", source_default.cyan("bagdock login"), "first.");
|
|
3440
|
+
process.exit(1);
|
|
3441
|
+
}
|
|
3442
|
+
if (name) {
|
|
3443
|
+
if (switchProfile(name)) {
|
|
3444
|
+
if (isJsonMode()) {
|
|
3445
|
+
outputSuccess({ active_profile: name });
|
|
3446
|
+
} else {
|
|
3447
|
+
console.log(source_default.green(`Switched to profile "${name}".`));
|
|
3448
|
+
}
|
|
3449
|
+
} else {
|
|
3450
|
+
outputError("NOT_FOUND", `Profile "${name}" not found. Available: ${profiles.map((p) => p.name).join(", ")}`);
|
|
3451
|
+
}
|
|
3452
|
+
return;
|
|
3453
|
+
}
|
|
3454
|
+
if (!process.stdout.isTTY) {
|
|
3455
|
+
outputError("MISSING_PROFILE", "Pass a profile name in non-interactive mode: bagdock auth switch <name>");
|
|
3456
|
+
}
|
|
3457
|
+
console.log(source_default.cyan(`
|
|
3458
|
+
Available profiles:
|
|
3459
|
+
`));
|
|
3460
|
+
profiles.forEach((p, i) => {
|
|
3461
|
+
const marker = p.active ? source_default.green("* ") : " ";
|
|
3462
|
+
const email = p.email ? source_default.dim(` (${p.email})`) : "";
|
|
3463
|
+
console.log(` ${marker}${i + 1}. ${p.name}${email}`);
|
|
3464
|
+
});
|
|
3465
|
+
const readline = await import("readline");
|
|
3466
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
3467
|
+
const answer = await new Promise((resolve) => {
|
|
3468
|
+
rl.question(source_default.cyan(`
|
|
3469
|
+
Enter profile number or name: `), resolve);
|
|
3470
|
+
});
|
|
3471
|
+
rl.close();
|
|
3472
|
+
const idx = parseInt(answer, 10);
|
|
3473
|
+
const target = idx > 0 && idx <= profiles.length ? profiles[idx - 1].name : answer.trim();
|
|
3474
|
+
if (switchProfile(target)) {
|
|
3475
|
+
console.log(source_default.green(`
|
|
3476
|
+
Switched to profile "${target}".
|
|
3477
|
+
`));
|
|
3478
|
+
} else {
|
|
3479
|
+
console.log(source_default.red(`
|
|
3480
|
+
Profile "${target}" not found.
|
|
3481
|
+
`));
|
|
3482
|
+
process.exit(1);
|
|
3483
|
+
}
|
|
3484
|
+
}
|
|
3288
3485
|
function sleep(ms) {
|
|
3289
3486
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
3290
3487
|
}
|
|
@@ -3292,64 +3489,136 @@ var apiKeyOverride, CLIENT_ID = "bagdock-cli", MAX_POLL_DURATION_MS = 300000;
|
|
|
3292
3489
|
var init_auth = __esm(() => {
|
|
3293
3490
|
init_config();
|
|
3294
3491
|
init_source();
|
|
3492
|
+
init_output();
|
|
3295
3493
|
});
|
|
3296
3494
|
|
|
3297
|
-
// src/
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3495
|
+
// src/doctor.ts
|
|
3496
|
+
var exports_doctor = {};
|
|
3497
|
+
__export(exports_doctor, {
|
|
3498
|
+
doctor: () => doctor
|
|
3499
|
+
});
|
|
3500
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
3501
|
+
import { join as join3, dirname } from "path";
|
|
3502
|
+
import { homedir as homedir2, platform as platform2 } from "os";
|
|
3503
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3504
|
+
function maskKey(key) {
|
|
3505
|
+
if (key.length <= 12)
|
|
3506
|
+
return key.slice(0, 4) + "...";
|
|
3507
|
+
return key.slice(0, 8) + "..." + key.slice(-4);
|
|
3508
|
+
}
|
|
3509
|
+
function getLocalVersion() {
|
|
3510
|
+
try {
|
|
3511
|
+
const pkgPath = join3(dirname(fileURLToPath2(import.meta.url)), "..", "package.json");
|
|
3512
|
+
const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
|
|
3513
|
+
return pkg.version ?? "unknown";
|
|
3514
|
+
} catch {
|
|
3515
|
+
return "unknown";
|
|
3302
3516
|
}
|
|
3303
|
-
|
|
3304
|
-
|
|
3517
|
+
}
|
|
3518
|
+
async function checkVersion() {
|
|
3519
|
+
const local = getLocalVersion();
|
|
3520
|
+
try {
|
|
3521
|
+
const res = await fetch("https://registry.npmjs.org/@bagdock/cli/latest", {
|
|
3522
|
+
signal: AbortSignal.timeout(5000)
|
|
3523
|
+
});
|
|
3524
|
+
if (res.ok) {
|
|
3525
|
+
const data = await res.json();
|
|
3526
|
+
if (data.version === local) {
|
|
3527
|
+
return { name: "CLI Version", status: "pass", message: `v${local} (latest)` };
|
|
3528
|
+
}
|
|
3529
|
+
return { name: "CLI Version", status: "warn", message: `v${local} (update available: v${data.version})` };
|
|
3530
|
+
}
|
|
3531
|
+
} catch {}
|
|
3532
|
+
return { name: "CLI Version", status: "pass", message: `v${local} (registry unreachable)` };
|
|
3533
|
+
}
|
|
3534
|
+
function checkAuth() {
|
|
3535
|
+
const { token, source } = getAuthSource();
|
|
3536
|
+
if (!token) {
|
|
3537
|
+
return { name: "API Key", status: "fail", message: "No API key found. Run `bagdock login` or set BAGDOCK_API_KEY." };
|
|
3305
3538
|
}
|
|
3539
|
+
return { name: "API Key", status: "pass", message: `${maskKey(token)} (source: ${source})` };
|
|
3306
3540
|
}
|
|
3307
|
-
function
|
|
3308
|
-
|
|
3541
|
+
function checkProjectConfig() {
|
|
3542
|
+
const config = loadBagdockJson(process.cwd());
|
|
3543
|
+
if (!config) {
|
|
3544
|
+
return { name: "Project Config", status: "warn", message: "No bagdock.json found in current directory" };
|
|
3545
|
+
}
|
|
3546
|
+
const issues = [];
|
|
3547
|
+
if (!config.slug)
|
|
3548
|
+
issues.push("missing slug");
|
|
3549
|
+
if (!config.type)
|
|
3550
|
+
issues.push("missing type");
|
|
3551
|
+
if (!config.main)
|
|
3552
|
+
issues.push("missing main");
|
|
3553
|
+
if (issues.length) {
|
|
3554
|
+
return { name: "Project Config", status: "warn", message: `bagdock.json has issues: ${issues.join(", ")}` };
|
|
3555
|
+
}
|
|
3556
|
+
return { name: "Project Config", status: "pass", message: `${config.slug} (${config.type}/${config.kind ?? config.category})` };
|
|
3309
3557
|
}
|
|
3310
|
-
function
|
|
3311
|
-
|
|
3558
|
+
function checkAgents() {
|
|
3559
|
+
const detected = [];
|
|
3560
|
+
const home = homedir2();
|
|
3561
|
+
if (existsSync3(join3(home, ".cursor")))
|
|
3562
|
+
detected.push("Cursor");
|
|
3563
|
+
if (existsSync3(join3(home, ".windsurf")))
|
|
3564
|
+
detected.push("Windsurf");
|
|
3565
|
+
if (existsSync3(join3(home, "clawd", "skills")) || existsSync3(join3(home, ".codex")))
|
|
3566
|
+
detected.push("OpenClaw/Codex");
|
|
3567
|
+
const p = platform2();
|
|
3568
|
+
if (p === "darwin" && existsSync3(join3(home, "Library", "Application Support", "Claude", "claude_desktop_config.json"))) {
|
|
3569
|
+
detected.push("Claude Desktop");
|
|
3570
|
+
} else if (p === "win32" && existsSync3(join3(process.env.APPDATA ?? "", "Claude", "claude_desktop_config.json"))) {
|
|
3571
|
+
detected.push("Claude Desktop");
|
|
3572
|
+
} else if (p === "linux" && existsSync3(join3(home, ".config", "Claude", "claude_desktop_config.json"))) {
|
|
3573
|
+
detected.push("Claude Desktop");
|
|
3574
|
+
}
|
|
3575
|
+
if (existsSync3(join3(process.cwd(), ".vscode", "mcp.json")))
|
|
3576
|
+
detected.push("VS Code");
|
|
3577
|
+
if (!detected.length) {
|
|
3578
|
+
return { name: "AI Agents", status: "pass", message: "None detected" };
|
|
3579
|
+
}
|
|
3580
|
+
return { name: "AI Agents", status: "pass", message: `Detected: ${detected.join(", ")}` };
|
|
3312
3581
|
}
|
|
3313
|
-
function
|
|
3582
|
+
async function doctor() {
|
|
3583
|
+
const checks = [];
|
|
3314
3584
|
if (isJsonMode()) {
|
|
3315
|
-
|
|
3316
|
-
|
|
3585
|
+
checks.push(await checkVersion());
|
|
3586
|
+
checks.push(checkAuth());
|
|
3587
|
+
checks.push(checkProjectConfig());
|
|
3588
|
+
checks.push(checkAgents());
|
|
3589
|
+
const ok = checks.every((c) => c.status !== "fail");
|
|
3590
|
+
outputSuccess({ ok, checks });
|
|
3591
|
+
return;
|
|
3317
3592
|
}
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3593
|
+
console.log(source_default.bold(`
|
|
3594
|
+
Bagdock Doctor
|
|
3595
|
+
`));
|
|
3596
|
+
process.stdout.write(" Checking CLI version...");
|
|
3597
|
+
const versionCheck = await checkVersion();
|
|
3598
|
+
checks.push(versionCheck);
|
|
3599
|
+
process.stdout.write(`\r ${ICON[versionCheck.status]} ${versionCheck.name}: ${versionCheck.message}
|
|
3325
3600
|
`);
|
|
3601
|
+
const authCheck = checkAuth();
|
|
3602
|
+
checks.push(authCheck);
|
|
3603
|
+
console.log(` ${ICON[authCheck.status]} ${authCheck.name}: ${authCheck.message}`);
|
|
3604
|
+
const configCheck = checkProjectConfig();
|
|
3605
|
+
checks.push(configCheck);
|
|
3606
|
+
console.log(` ${ICON[configCheck.status]} ${configCheck.name}: ${configCheck.message}`);
|
|
3607
|
+
const agentCheck = checkAgents();
|
|
3608
|
+
checks.push(agentCheck);
|
|
3609
|
+
console.log(` ${ICON[agentCheck.status]} ${agentCheck.name}: ${agentCheck.message}`);
|
|
3610
|
+
console.log();
|
|
3611
|
+
const hasFail = checks.some((c) => c.status === "fail");
|
|
3612
|
+
if (hasFail)
|
|
3326
3613
|
process.exit(1);
|
|
3327
|
-
} else {
|
|
3328
|
-
console.error(source_default.red(`Error [${code}]:`), message);
|
|
3329
|
-
if (details)
|
|
3330
|
-
console.error(details);
|
|
3331
|
-
process.exit(1);
|
|
3332
|
-
}
|
|
3333
|
-
}
|
|
3334
|
-
function outputList(objectType, data, hasMore) {
|
|
3335
|
-
if (isJsonMode()) {
|
|
3336
|
-
process.stdout.write(JSON.stringify({ object: "list", data, has_more: hasMore }, null, 2) + `
|
|
3337
|
-
`);
|
|
3338
|
-
}
|
|
3339
|
-
}
|
|
3340
|
-
function status(message) {
|
|
3341
|
-
if (!isQuiet() && !isJsonMode()) {
|
|
3342
|
-
console.log(source_default.dim(message));
|
|
3343
|
-
}
|
|
3344
3614
|
}
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
console.log(source_default.green(message));
|
|
3348
|
-
}
|
|
3349
|
-
}
|
|
3350
|
-
var forceJson = false, quiet = false;
|
|
3351
|
-
var init_output = __esm(() => {
|
|
3615
|
+
var ICON;
|
|
3616
|
+
var init_doctor = __esm(() => {
|
|
3352
3617
|
init_source();
|
|
3618
|
+
init_auth();
|
|
3619
|
+
init_config();
|
|
3620
|
+
init_output();
|
|
3621
|
+
ICON = { pass: source_default.green("✔"), warn: source_default.yellow("!"), fail: source_default.red("✘") };
|
|
3353
3622
|
});
|
|
3354
3623
|
|
|
3355
3624
|
// src/dev.ts
|
|
@@ -3357,8 +3626,8 @@ var exports_dev = {};
|
|
|
3357
3626
|
__export(exports_dev, {
|
|
3358
3627
|
dev: () => dev
|
|
3359
3628
|
});
|
|
3360
|
-
import { existsSync as
|
|
3361
|
-
import { join as
|
|
3629
|
+
import { existsSync as existsSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
3630
|
+
import { join as join4 } from "path";
|
|
3362
3631
|
import { spawn } from "child_process";
|
|
3363
3632
|
async function dev(opts) {
|
|
3364
3633
|
const cwd = process.cwd();
|
|
@@ -3369,11 +3638,11 @@ async function dev(opts) {
|
|
|
3369
3638
|
}
|
|
3370
3639
|
const port = opts.port ?? "8787";
|
|
3371
3640
|
const wranglerToml = generateWranglerToml(config, port);
|
|
3372
|
-
const wranglerPath =
|
|
3641
|
+
const wranglerPath = join4(cwd, "wrangler.toml");
|
|
3373
3642
|
writeFileSync3(wranglerPath, wranglerToml);
|
|
3374
3643
|
console.log(source_default.green("Generated"), source_default.cyan("wrangler.toml"), source_default.green("from bagdock.json"));
|
|
3375
|
-
const devVarsPath =
|
|
3376
|
-
if (!
|
|
3644
|
+
const devVarsPath = join4(cwd, ".dev.vars");
|
|
3645
|
+
if (!existsSync4(devVarsPath) && config.env) {
|
|
3377
3646
|
const hint = Object.entries(config.env).map(([key, meta]) => `# ${meta.description ?? key}${meta.required ? " (required)" : ""}
|
|
3378
3647
|
${key}=`).join(`
|
|
3379
3648
|
`);
|
|
@@ -3434,8 +3703,8 @@ var exports_deploy = {};
|
|
|
3434
3703
|
__export(exports_deploy, {
|
|
3435
3704
|
deploy: () => deploy
|
|
3436
3705
|
});
|
|
3437
|
-
import { existsSync as
|
|
3438
|
-
import { join as
|
|
3706
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
|
|
3707
|
+
import { join as join5 } from "path";
|
|
3439
3708
|
import { execSync } from "child_process";
|
|
3440
3709
|
import { createInterface } from "readline";
|
|
3441
3710
|
async function deploy(opts) {
|
|
@@ -3476,8 +3745,8 @@ async function deploy(opts) {
|
|
|
3476
3745
|
console.log(source_default.cyan(`
|
|
3477
3746
|
Deploying ${config.slug}@${config.version} → ${envLabel}
|
|
3478
3747
|
`));
|
|
3479
|
-
const outDir =
|
|
3480
|
-
const outFile =
|
|
3748
|
+
const outDir = join5(cwd, ".bagdock");
|
|
3749
|
+
const outFile = join5(outDir, "worker.mjs");
|
|
3481
3750
|
console.log(source_default.dim(" Building worker bundle..."));
|
|
3482
3751
|
execSync(`mkdir -p ${outDir}`, { cwd });
|
|
3483
3752
|
try {
|
|
@@ -3493,11 +3762,11 @@ Deploying ${config.slug}@${config.version} → ${envLabel}
|
|
|
3493
3762
|
process.exit(1);
|
|
3494
3763
|
}
|
|
3495
3764
|
}
|
|
3496
|
-
if (!
|
|
3765
|
+
if (!existsSync5(outFile)) {
|
|
3497
3766
|
console.error(source_default.red(" Build output not found at"), outFile);
|
|
3498
3767
|
process.exit(1);
|
|
3499
3768
|
}
|
|
3500
|
-
const scriptContent =
|
|
3769
|
+
const scriptContent = readFileSync3(outFile);
|
|
3501
3770
|
const sizeKb = (scriptContent.length / 1024).toFixed(1);
|
|
3502
3771
|
console.log(source_default.dim(` Bundle size: ${sizeKb} KB`));
|
|
3503
3772
|
console.log(source_default.dim(" Uploading to Bagdock platform..."));
|
|
@@ -3625,14 +3894,430 @@ var init_submit = __esm(() => {
|
|
|
3625
3894
|
init_auth();
|
|
3626
3895
|
});
|
|
3627
3896
|
|
|
3897
|
+
// src/link.ts
|
|
3898
|
+
var exports_link = {};
|
|
3899
|
+
__export(exports_link, {
|
|
3900
|
+
resolveSlug: () => resolveSlug,
|
|
3901
|
+
requireSlug: () => requireSlug,
|
|
3902
|
+
link: () => link
|
|
3903
|
+
});
|
|
3904
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
3905
|
+
import { join as join6 } from "path";
|
|
3906
|
+
function resolveSlug() {
|
|
3907
|
+
const config = loadBagdockJson(process.cwd());
|
|
3908
|
+
if (config?.slug)
|
|
3909
|
+
return config.slug;
|
|
3910
|
+
const linkPath = join6(process.cwd(), LINK_DIR, LINK_FILE);
|
|
3911
|
+
if (existsSync6(linkPath)) {
|
|
3912
|
+
try {
|
|
3913
|
+
const data = JSON.parse(readFileSync4(linkPath, "utf-8"));
|
|
3914
|
+
return data.slug ?? null;
|
|
3915
|
+
} catch {
|
|
3916
|
+
return null;
|
|
3917
|
+
}
|
|
3918
|
+
}
|
|
3919
|
+
return null;
|
|
3920
|
+
}
|
|
3921
|
+
function requireSlug(slugArg) {
|
|
3922
|
+
const slug = slugArg ?? resolveSlug();
|
|
3923
|
+
if (!slug) {
|
|
3924
|
+
if (isJsonMode()) {
|
|
3925
|
+
outputError("no_project", "No project found. Pass --slug, add bagdock.json, or run bagdock link.");
|
|
3926
|
+
}
|
|
3927
|
+
console.error(source_default.red("No project found."), "Pass a slug, create bagdock.json, or run", source_default.cyan("bagdock link"));
|
|
3928
|
+
process.exit(1);
|
|
3929
|
+
}
|
|
3930
|
+
return slug;
|
|
3931
|
+
}
|
|
3932
|
+
async function link(opts) {
|
|
3933
|
+
let slug = opts.slug;
|
|
3934
|
+
if (!slug) {
|
|
3935
|
+
const config = loadBagdockJson(process.cwd());
|
|
3936
|
+
if (config?.slug) {
|
|
3937
|
+
slug = config.slug;
|
|
3938
|
+
status(`Found bagdock.json — linking to ${slug}`);
|
|
3939
|
+
}
|
|
3940
|
+
}
|
|
3941
|
+
if (!slug && process.stdout.isTTY && !isJsonMode()) {
|
|
3942
|
+
const token = getAuthToken();
|
|
3943
|
+
if (!token) {
|
|
3944
|
+
console.error(source_default.red("Not authenticated."), "Run", source_default.cyan("bagdock login"), "first.");
|
|
3945
|
+
process.exit(1);
|
|
3946
|
+
}
|
|
3947
|
+
status("Fetching your apps...");
|
|
3948
|
+
try {
|
|
3949
|
+
const res = await fetch(`${API_BASE}/v1/developer/apps`, {
|
|
3950
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
3951
|
+
});
|
|
3952
|
+
if (!res.ok)
|
|
3953
|
+
throw new Error(`API returned ${res.status}`);
|
|
3954
|
+
const { data } = await res.json();
|
|
3955
|
+
if (!data?.length) {
|
|
3956
|
+
console.error(source_default.yellow("No apps found."), "Create one with", source_default.cyan("bagdock init"));
|
|
3957
|
+
process.exit(1);
|
|
3958
|
+
}
|
|
3959
|
+
console.log(source_default.bold(`
|
|
3960
|
+
Your apps:
|
|
3961
|
+
`));
|
|
3962
|
+
data.forEach((app, i) => console.log(` ${source_default.cyan(i + 1)} ${app.name} ${source_default.dim(`(${app.slug})`)}`));
|
|
3963
|
+
console.log();
|
|
3964
|
+
const readline = await import("readline");
|
|
3965
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
3966
|
+
const answer = await new Promise((resolve) => rl.question("Select app number: ", resolve));
|
|
3967
|
+
rl.close();
|
|
3968
|
+
const idx = parseInt(answer, 10) - 1;
|
|
3969
|
+
if (isNaN(idx) || idx < 0 || idx >= data.length) {
|
|
3970
|
+
console.error(source_default.red("Invalid selection"));
|
|
3971
|
+
process.exit(1);
|
|
3972
|
+
}
|
|
3973
|
+
slug = data[idx].slug;
|
|
3974
|
+
} catch (err) {
|
|
3975
|
+
console.error(source_default.red("Failed to fetch apps:"), err.message);
|
|
3976
|
+
process.exit(1);
|
|
3977
|
+
}
|
|
3978
|
+
}
|
|
3979
|
+
if (!slug) {
|
|
3980
|
+
outputError("missing_slug", "Slug required. Pass --slug in non-interactive mode.");
|
|
3981
|
+
process.exit(1);
|
|
3982
|
+
}
|
|
3983
|
+
const dir = join6(process.cwd(), LINK_DIR);
|
|
3984
|
+
if (!existsSync6(dir))
|
|
3985
|
+
mkdirSync3(dir, { recursive: true });
|
|
3986
|
+
const linkData = { slug, linkedAt: new Date().toISOString() };
|
|
3987
|
+
writeFileSync4(join6(dir, LINK_FILE), JSON.stringify(linkData, null, 2));
|
|
3988
|
+
if (isJsonMode()) {
|
|
3989
|
+
outputSuccess({ slug, path: join6(dir, LINK_FILE) });
|
|
3990
|
+
} else {
|
|
3991
|
+
console.log(source_default.green(`Linked to ${source_default.bold(slug)}`));
|
|
3992
|
+
console.log(source_default.dim(` Stored in ${LINK_DIR}/${LINK_FILE}`));
|
|
3993
|
+
}
|
|
3994
|
+
}
|
|
3995
|
+
var LINK_DIR = ".bagdock", LINK_FILE = "link.json";
|
|
3996
|
+
var init_link = __esm(() => {
|
|
3997
|
+
init_source();
|
|
3998
|
+
init_config();
|
|
3999
|
+
init_auth();
|
|
4000
|
+
init_output();
|
|
4001
|
+
});
|
|
4002
|
+
|
|
4003
|
+
// src/validate.ts
|
|
4004
|
+
var exports_validate = {};
|
|
4005
|
+
__export(exports_validate, {
|
|
4006
|
+
validate: () => validate
|
|
4007
|
+
});
|
|
4008
|
+
import { existsSync as existsSync7, statSync } from "fs";
|
|
4009
|
+
import { join as join7 } from "path";
|
|
4010
|
+
async function validate() {
|
|
4011
|
+
const checks = [];
|
|
4012
|
+
const dir = process.cwd();
|
|
4013
|
+
const config = loadBagdockJson(dir);
|
|
4014
|
+
if (!config) {
|
|
4015
|
+
checks.push({ name: "bagdock.json", status: "fail", message: "Not found or invalid JSON" });
|
|
4016
|
+
return finish(checks);
|
|
4017
|
+
}
|
|
4018
|
+
checks.push({ name: "bagdock.json", status: "pass", message: "Found and parsed" });
|
|
4019
|
+
const required = ["name", "slug", "version", "type", "category", "main"];
|
|
4020
|
+
const missing = required.filter((f) => !config[f]);
|
|
4021
|
+
if (missing.length) {
|
|
4022
|
+
checks.push({ name: "Required fields", status: "fail", message: `Missing: ${missing.join(", ")}` });
|
|
4023
|
+
} else {
|
|
4024
|
+
checks.push({ name: "Required fields", status: "pass", message: "All present" });
|
|
4025
|
+
}
|
|
4026
|
+
if (!VALID_TYPES.includes(config.type)) {
|
|
4027
|
+
checks.push({ name: "Type", status: "fail", message: `Invalid type "${config.type}". Must be: ${VALID_TYPES.join(", ")}` });
|
|
4028
|
+
} else {
|
|
4029
|
+
checks.push({ name: "Type", status: "pass", message: config.type });
|
|
4030
|
+
}
|
|
4031
|
+
if (config.kind && !VALID_KINDS.includes(config.kind)) {
|
|
4032
|
+
checks.push({ name: "Kind", status: "warn", message: `Unknown kind "${config.kind}". Expected: ${VALID_KINDS.join(", ")}` });
|
|
4033
|
+
}
|
|
4034
|
+
const entryPath = join7(dir, config.main);
|
|
4035
|
+
if (!existsSync7(entryPath)) {
|
|
4036
|
+
checks.push({ name: "Entry point", status: "fail", message: `File not found: ${config.main}` });
|
|
4037
|
+
} else {
|
|
4038
|
+
const size = statSync(entryPath).size;
|
|
4039
|
+
checks.push({ name: "Entry point", status: "pass", message: `${config.main} (${(size / 1024).toFixed(1)} KB)` });
|
|
4040
|
+
if (size > MAX_BUNDLE_BYTES) {
|
|
4041
|
+
checks.push({ name: "Bundle size", status: "fail", message: `${(size / 1024 / 1024).toFixed(1)} MB exceeds ${MAX_BUNDLE_BYTES / 1024 / 1024} MB limit` });
|
|
4042
|
+
} else if (size > MAX_BUNDLE_BYTES * 0.8) {
|
|
4043
|
+
checks.push({ name: "Bundle size", status: "warn", message: `${(size / 1024 / 1024).toFixed(1)} MB — approaching limit` });
|
|
4044
|
+
} else {
|
|
4045
|
+
checks.push({ name: "Bundle size", status: "pass", message: `${(size / 1024).toFixed(1)} KB` });
|
|
4046
|
+
}
|
|
4047
|
+
}
|
|
4048
|
+
const linked = resolveSlug();
|
|
4049
|
+
if (linked && linked !== config.slug) {
|
|
4050
|
+
checks.push({ name: "Project link", status: "warn", message: `bagdock.json slug "${config.slug}" differs from linked project "${linked}"` });
|
|
4051
|
+
}
|
|
4052
|
+
return finish(checks);
|
|
4053
|
+
}
|
|
4054
|
+
function finish(checks) {
|
|
4055
|
+
const hasFail = checks.some((c) => c.status === "fail");
|
|
4056
|
+
const hasWarn = checks.some((c) => c.status === "warn");
|
|
4057
|
+
if (isJsonMode()) {
|
|
4058
|
+
outputSuccess({ ok: !hasFail, checks });
|
|
4059
|
+
if (hasFail)
|
|
4060
|
+
process.exit(1);
|
|
4061
|
+
return;
|
|
4062
|
+
}
|
|
4063
|
+
console.log(source_default.bold(`
|
|
4064
|
+
Bagdock Validate
|
|
4065
|
+
`));
|
|
4066
|
+
for (const c of checks) {
|
|
4067
|
+
const icon = c.status === "pass" ? source_default.green("✔") : c.status === "warn" ? source_default.yellow("⚠") : source_default.red("✖");
|
|
4068
|
+
console.log(` ${icon} ${c.name}: ${c.message}`);
|
|
4069
|
+
}
|
|
4070
|
+
console.log();
|
|
4071
|
+
if (hasFail) {
|
|
4072
|
+
console.log(source_default.red(` Validation failed. Fix errors before submitting.
|
|
4073
|
+
`));
|
|
4074
|
+
process.exit(1);
|
|
4075
|
+
} else if (hasWarn) {
|
|
4076
|
+
console.log(source_default.yellow(` Passed with warnings.
|
|
4077
|
+
`));
|
|
4078
|
+
} else {
|
|
4079
|
+
console.log(source_default.green(` All checks passed. Ready to submit.
|
|
4080
|
+
`));
|
|
4081
|
+
}
|
|
4082
|
+
}
|
|
4083
|
+
var VALID_TYPES, VALID_KINDS, MAX_BUNDLE_BYTES;
|
|
4084
|
+
var init_validate = __esm(() => {
|
|
4085
|
+
init_source();
|
|
4086
|
+
init_config();
|
|
4087
|
+
init_output();
|
|
4088
|
+
init_link();
|
|
4089
|
+
VALID_TYPES = ["edge", "app"];
|
|
4090
|
+
VALID_KINDS = ["adapter", "comms", "webhook", "ui-extension", "microfrontend"];
|
|
4091
|
+
MAX_BUNDLE_BYTES = 10 * 1024 * 1024;
|
|
4092
|
+
});
|
|
4093
|
+
|
|
4094
|
+
// src/submission.ts
|
|
4095
|
+
var exports_submission = {};
|
|
4096
|
+
__export(exports_submission, {
|
|
4097
|
+
submissionWithdraw: () => submissionWithdraw,
|
|
4098
|
+
submissionStatus: () => submissionStatus,
|
|
4099
|
+
submissionList: () => submissionList
|
|
4100
|
+
});
|
|
4101
|
+
function requireAuth() {
|
|
4102
|
+
const token = getAuthToken();
|
|
4103
|
+
if (!token) {
|
|
4104
|
+
outputError("auth_error", "Not authenticated. Run bagdock login or set BAGDOCK_API_KEY.");
|
|
4105
|
+
process.exit(1);
|
|
4106
|
+
}
|
|
4107
|
+
return token;
|
|
4108
|
+
}
|
|
4109
|
+
async function submissionList(opts) {
|
|
4110
|
+
const token = requireAuth();
|
|
4111
|
+
const slug = requireSlug(opts.app);
|
|
4112
|
+
status(`Fetching submissions for ${slug}...`);
|
|
4113
|
+
try {
|
|
4114
|
+
const res = await fetch(`${API_BASE}/v1/developer/apps/${slug}/submissions`, {
|
|
4115
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
4116
|
+
});
|
|
4117
|
+
if (res.status === 404) {
|
|
4118
|
+
outputError("not_found", `App "${slug}" not found or no submissions exist.`);
|
|
4119
|
+
}
|
|
4120
|
+
if (!res.ok) {
|
|
4121
|
+
outputError("api_error", `API returned ${res.status}`);
|
|
4122
|
+
}
|
|
4123
|
+
const { data } = await res.json();
|
|
4124
|
+
if (isJsonMode()) {
|
|
4125
|
+
outputList("submission", data, false);
|
|
4126
|
+
return;
|
|
4127
|
+
}
|
|
4128
|
+
if (!data?.length) {
|
|
4129
|
+
console.log(source_default.yellow("No submissions found for this app."));
|
|
4130
|
+
console.log("Submit with", source_default.cyan("bagdock submit"));
|
|
4131
|
+
return;
|
|
4132
|
+
}
|
|
4133
|
+
console.log(source_default.bold(`
|
|
4134
|
+
Submissions for ${slug}:
|
|
4135
|
+
`));
|
|
4136
|
+
console.log(` ${"ID".padEnd(22)} ${"Version".padEnd(10)} ${"Reason".padEnd(30)} ${"Date"}`);
|
|
4137
|
+
console.log(source_default.dim(" " + "─".repeat(80)));
|
|
4138
|
+
for (const s of data) {
|
|
4139
|
+
console.log(` ${source_default.cyan(s.id.padEnd(22))} ${(s.version ?? "").padEnd(10)} ${(s.change_reason ?? "").slice(0, 30).padEnd(30)} ${source_default.dim(new Date(s.created_at).toLocaleDateString())}`);
|
|
4140
|
+
}
|
|
4141
|
+
console.log();
|
|
4142
|
+
} catch (err) {
|
|
4143
|
+
outputError("network_error", err.message);
|
|
4144
|
+
}
|
|
4145
|
+
}
|
|
4146
|
+
async function submissionStatus(id, opts) {
|
|
4147
|
+
const token = requireAuth();
|
|
4148
|
+
const slug = requireSlug(opts.app);
|
|
4149
|
+
status(`Fetching submission ${id}...`);
|
|
4150
|
+
try {
|
|
4151
|
+
const res = await fetch(`${API_BASE}/v1/developer/apps/${slug}/submissions/${id}`, {
|
|
4152
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
4153
|
+
});
|
|
4154
|
+
if (res.status === 404) {
|
|
4155
|
+
outputError("not_found", `Submission "${id}" not found.`);
|
|
4156
|
+
}
|
|
4157
|
+
if (!res.ok) {
|
|
4158
|
+
outputError("api_error", `API returned ${res.status}`);
|
|
4159
|
+
}
|
|
4160
|
+
const { data } = await res.json();
|
|
4161
|
+
if (isJsonMode()) {
|
|
4162
|
+
outputSuccess(data);
|
|
4163
|
+
return;
|
|
4164
|
+
}
|
|
4165
|
+
console.log(source_default.bold(`
|
|
4166
|
+
Submission ${source_default.cyan(data.id)}
|
|
4167
|
+
`));
|
|
4168
|
+
const fields = [
|
|
4169
|
+
["App", `${data.name} (${data.slug})`],
|
|
4170
|
+
["Version", data.version],
|
|
4171
|
+
["Review Status", data.review_status],
|
|
4172
|
+
["Type", data.type],
|
|
4173
|
+
["Visibility", data.visibility],
|
|
4174
|
+
["Reason", data.change_reason],
|
|
4175
|
+
["Submitted by", data.changed_by],
|
|
4176
|
+
["Date", new Date(data.created_at).toLocaleString()]
|
|
4177
|
+
];
|
|
4178
|
+
for (const [label, value] of fields) {
|
|
4179
|
+
console.log(` ${source_default.dim(label.padEnd(16))} ${value ?? source_default.dim("—")}`);
|
|
4180
|
+
}
|
|
4181
|
+
console.log();
|
|
4182
|
+
} catch (err) {
|
|
4183
|
+
outputError("network_error", err.message);
|
|
4184
|
+
}
|
|
4185
|
+
}
|
|
4186
|
+
async function submissionWithdraw(id, opts) {
|
|
4187
|
+
const token = requireAuth();
|
|
4188
|
+
const slug = requireSlug(opts.app);
|
|
4189
|
+
status(`Withdrawing submission ${id}...`);
|
|
4190
|
+
try {
|
|
4191
|
+
const res = await fetch(`${API_BASE}/v1/developer/apps/${slug}/submissions/${id}/withdraw`, {
|
|
4192
|
+
method: "POST",
|
|
4193
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
4194
|
+
});
|
|
4195
|
+
if (res.status === 404) {
|
|
4196
|
+
outputError("not_found", `App "${slug}" not found.`);
|
|
4197
|
+
}
|
|
4198
|
+
if (res.status === 409) {
|
|
4199
|
+
const body = await res.json();
|
|
4200
|
+
outputError(body.code ?? "invalid_status", body.message);
|
|
4201
|
+
}
|
|
4202
|
+
if (!res.ok) {
|
|
4203
|
+
outputError("api_error", `API returned ${res.status}`);
|
|
4204
|
+
}
|
|
4205
|
+
const { data } = await res.json();
|
|
4206
|
+
if (isJsonMode()) {
|
|
4207
|
+
outputSuccess(data);
|
|
4208
|
+
return;
|
|
4209
|
+
}
|
|
4210
|
+
console.log(source_default.green(`Submission withdrawn.`), source_default.dim(`Status is now: ${data.review_status}`));
|
|
4211
|
+
console.log("You can re-submit with", source_default.cyan("bagdock submit"));
|
|
4212
|
+
} catch (err) {
|
|
4213
|
+
outputError("network_error", err.message);
|
|
4214
|
+
}
|
|
4215
|
+
}
|
|
4216
|
+
var init_submission = __esm(() => {
|
|
4217
|
+
init_source();
|
|
4218
|
+
init_config();
|
|
4219
|
+
init_auth();
|
|
4220
|
+
init_output();
|
|
4221
|
+
init_link();
|
|
4222
|
+
});
|
|
4223
|
+
|
|
4224
|
+
// src/open.ts
|
|
4225
|
+
var exports_open2 = {};
|
|
4226
|
+
__export(exports_open2, {
|
|
4227
|
+
open: () => open2
|
|
4228
|
+
});
|
|
4229
|
+
async function open2(slugArg) {
|
|
4230
|
+
const slug = requireSlug(slugArg);
|
|
4231
|
+
const url = `${DASHBOARD_BASE}/developer/apps/${slug}`;
|
|
4232
|
+
if (isJsonMode()) {
|
|
4233
|
+
outputSuccess({ url, slug });
|
|
4234
|
+
return;
|
|
4235
|
+
}
|
|
4236
|
+
status(`Opening ${url}`);
|
|
4237
|
+
await open_default(url);
|
|
4238
|
+
console.log(source_default.green("Opened"), source_default.cyan(url));
|
|
4239
|
+
}
|
|
4240
|
+
var init_open2 = __esm(() => {
|
|
4241
|
+
init_source();
|
|
4242
|
+
init_open();
|
|
4243
|
+
init_config();
|
|
4244
|
+
init_output();
|
|
4245
|
+
init_link();
|
|
4246
|
+
});
|
|
4247
|
+
|
|
4248
|
+
// src/inspect.ts
|
|
4249
|
+
var exports_inspect = {};
|
|
4250
|
+
__export(exports_inspect, {
|
|
4251
|
+
inspect: () => inspect
|
|
4252
|
+
});
|
|
4253
|
+
async function inspect(slugArg) {
|
|
4254
|
+
const token = getAuthToken();
|
|
4255
|
+
if (!token) {
|
|
4256
|
+
outputError("auth_error", "Not authenticated. Run bagdock login or set BAGDOCK_API_KEY.");
|
|
4257
|
+
process.exit(1);
|
|
4258
|
+
}
|
|
4259
|
+
const slug = requireSlug(slugArg);
|
|
4260
|
+
status(`Inspecting ${slug}...`);
|
|
4261
|
+
try {
|
|
4262
|
+
const res = await fetch(`${API_BASE}/v1/developer/apps/${slug}`, {
|
|
4263
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
4264
|
+
});
|
|
4265
|
+
if (res.status === 404)
|
|
4266
|
+
outputError("not_found", `App "${slug}" not found.`);
|
|
4267
|
+
if (!res.ok)
|
|
4268
|
+
outputError("api_error", `API returned ${res.status}`);
|
|
4269
|
+
const { data } = await res.json();
|
|
4270
|
+
if (isJsonMode()) {
|
|
4271
|
+
outputSuccess(data);
|
|
4272
|
+
return;
|
|
4273
|
+
}
|
|
4274
|
+
console.log(source_default.bold(`
|
|
4275
|
+
${data.name} ${source_default.dim(`(${data.slug})`)}
|
|
4276
|
+
`));
|
|
4277
|
+
const fields = [
|
|
4278
|
+
["ID", data.id],
|
|
4279
|
+
["Type", data.type],
|
|
4280
|
+
["Category", data.category],
|
|
4281
|
+
["Version", data.version],
|
|
4282
|
+
["Maintainer", data.maintainer],
|
|
4283
|
+
["Visibility", data.visibility],
|
|
4284
|
+
["Review Status", data.review_status],
|
|
4285
|
+
["Active", data.is_active ? "yes" : "no"],
|
|
4286
|
+
["Worker URL", data.worker_url],
|
|
4287
|
+
["Namespace", data.worker_namespace],
|
|
4288
|
+
["Created", data.created_at ? new Date(data.created_at).toLocaleString() : undefined],
|
|
4289
|
+
["Updated", data.updated_at ? new Date(data.updated_at).toLocaleString() : undefined],
|
|
4290
|
+
["Published", data.published_at ? new Date(data.published_at).toLocaleString() : undefined]
|
|
4291
|
+
];
|
|
4292
|
+
for (const [label, value] of fields) {
|
|
4293
|
+
if (value !== undefined && value !== null) {
|
|
4294
|
+
console.log(` ${source_default.dim(label.padEnd(16))} ${value}`);
|
|
4295
|
+
}
|
|
4296
|
+
}
|
|
4297
|
+
console.log();
|
|
4298
|
+
} catch (err) {
|
|
4299
|
+
outputError("network_error", err.message);
|
|
4300
|
+
}
|
|
4301
|
+
}
|
|
4302
|
+
var init_inspect = __esm(() => {
|
|
4303
|
+
init_source();
|
|
4304
|
+
init_config();
|
|
4305
|
+
init_auth();
|
|
4306
|
+
init_output();
|
|
4307
|
+
init_link();
|
|
4308
|
+
});
|
|
4309
|
+
|
|
3628
4310
|
// src/env-cmd.ts
|
|
3629
4311
|
var exports_env_cmd = {};
|
|
3630
4312
|
__export(exports_env_cmd, {
|
|
3631
4313
|
envSet: () => envSet,
|
|
3632
4314
|
envRemove: () => envRemove,
|
|
4315
|
+
envPull: () => envPull,
|
|
3633
4316
|
envList: () => envList
|
|
3634
4317
|
});
|
|
3635
|
-
|
|
4318
|
+
import { writeFileSync as writeFileSync5 } from "fs";
|
|
4319
|
+
import { resolve } from "path";
|
|
4320
|
+
function requireAuth2() {
|
|
3636
4321
|
const token = getAuthToken();
|
|
3637
4322
|
if (!token) {
|
|
3638
4323
|
console.error(source_default.red("Not authenticated. Run"), source_default.cyan("bagdock login"), source_default.red("or set BAGDOCK_API_KEY."));
|
|
@@ -3649,7 +4334,7 @@ function requireConfig() {
|
|
|
3649
4334
|
return config;
|
|
3650
4335
|
}
|
|
3651
4336
|
async function envList() {
|
|
3652
|
-
const token =
|
|
4337
|
+
const token = requireAuth2();
|
|
3653
4338
|
const config = requireConfig();
|
|
3654
4339
|
try {
|
|
3655
4340
|
const res = await fetch(`${API_BASE}/v1/developer/apps/${config.slug}/env`, {
|
|
@@ -3678,7 +4363,7 @@ Environment variables for ${config.slug}:
|
|
|
3678
4363
|
}
|
|
3679
4364
|
}
|
|
3680
4365
|
async function envSet(key, value) {
|
|
3681
|
-
const token =
|
|
4366
|
+
const token = requireAuth2();
|
|
3682
4367
|
const config = requireConfig();
|
|
3683
4368
|
try {
|
|
3684
4369
|
const res = await fetch(`${API_BASE}/v1/developer/apps/${config.slug}/env`, {
|
|
@@ -3701,7 +4386,7 @@ async function envSet(key, value) {
|
|
|
3701
4386
|
}
|
|
3702
4387
|
}
|
|
3703
4388
|
async function envRemove(key) {
|
|
3704
|
-
const token =
|
|
4389
|
+
const token = requireAuth2();
|
|
3705
4390
|
const config = requireConfig();
|
|
3706
4391
|
try {
|
|
3707
4392
|
const res = await fetch(`${API_BASE}/v1/developer/apps/${config.slug}/env/${key}`, {
|
|
@@ -3718,10 +4403,52 @@ async function envRemove(key) {
|
|
|
3718
4403
|
process.exit(1);
|
|
3719
4404
|
}
|
|
3720
4405
|
}
|
|
4406
|
+
async function envPull(file) {
|
|
4407
|
+
const token = requireAuth2();
|
|
4408
|
+
const slug = requireSlug();
|
|
4409
|
+
const target = resolve(file ?? ".env.local");
|
|
4410
|
+
status(`Pulling env vars for ${slug}...`);
|
|
4411
|
+
try {
|
|
4412
|
+
const res = await fetch(`${API_BASE}/v1/developer/apps/${slug}/env`, {
|
|
4413
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
4414
|
+
});
|
|
4415
|
+
if (!res.ok) {
|
|
4416
|
+
outputError("api_error", `Failed to pull env vars (${res.status})`);
|
|
4417
|
+
process.exit(1);
|
|
4418
|
+
}
|
|
4419
|
+
const { data } = await res.json();
|
|
4420
|
+
if (isJsonMode()) {
|
|
4421
|
+
outputSuccess({ file: target, keys: data.map((v) => v.key) });
|
|
4422
|
+
return;
|
|
4423
|
+
}
|
|
4424
|
+
if (!data?.length) {
|
|
4425
|
+
console.log(source_default.yellow("No environment variables set."));
|
|
4426
|
+
return;
|
|
4427
|
+
}
|
|
4428
|
+
const lines = [
|
|
4429
|
+
`# Pulled from Bagdock — ${slug}`,
|
|
4430
|
+
`# ${new Date().toISOString()}`,
|
|
4431
|
+
`# Values are placeholders — the API does not expose secrets.`,
|
|
4432
|
+
`# Fill in real values for local development.`,
|
|
4433
|
+
"",
|
|
4434
|
+
...data.map((v) => `${v.key}=`),
|
|
4435
|
+
""
|
|
4436
|
+
];
|
|
4437
|
+
writeFileSync5(target, lines.join(`
|
|
4438
|
+
`));
|
|
4439
|
+
console.log(source_default.green(`Wrote ${data.length} keys to ${target}`));
|
|
4440
|
+
console.log(source_default.yellow("Note:"), "Values are empty — fill them in for local dev.");
|
|
4441
|
+
} catch (err) {
|
|
4442
|
+
console.error(source_default.red("Failed:"), err.message);
|
|
4443
|
+
process.exit(1);
|
|
4444
|
+
}
|
|
4445
|
+
}
|
|
3721
4446
|
var init_env_cmd = __esm(() => {
|
|
3722
4447
|
init_source();
|
|
3723
4448
|
init_config();
|
|
3724
4449
|
init_auth();
|
|
4450
|
+
init_output();
|
|
4451
|
+
init_link();
|
|
3725
4452
|
});
|
|
3726
4453
|
|
|
3727
4454
|
// src/keys.ts
|
|
@@ -3940,7 +4667,7 @@ async function apiRequest3(method, path2) {
|
|
|
3940
4667
|
headers: { Authorization: `Bearer ${token}` }
|
|
3941
4668
|
});
|
|
3942
4669
|
}
|
|
3943
|
-
function
|
|
4670
|
+
function resolveSlug2(slug) {
|
|
3944
4671
|
if (slug)
|
|
3945
4672
|
return slug;
|
|
3946
4673
|
const config = loadBagdockJson(process.cwd());
|
|
@@ -3950,7 +4677,7 @@ function resolveSlug(slug) {
|
|
|
3950
4677
|
return "";
|
|
3951
4678
|
}
|
|
3952
4679
|
async function logsList(opts) {
|
|
3953
|
-
const slug =
|
|
4680
|
+
const slug = resolveSlug2(opts.app);
|
|
3954
4681
|
const limit = opts.limit || "50";
|
|
3955
4682
|
status(`Fetching logs for ${slug}...`);
|
|
3956
4683
|
const res = await apiRequest3("GET", `/api/v1/developer/apps/${slug}/logs?limit=${limit}`);
|
|
@@ -3981,7 +4708,7 @@ async function logsList(opts) {
|
|
|
3981
4708
|
}
|
|
3982
4709
|
}
|
|
3983
4710
|
async function logsGet(id, opts) {
|
|
3984
|
-
const slug =
|
|
4711
|
+
const slug = resolveSlug2(opts.app);
|
|
3985
4712
|
status(`Fetching log entry ${id}...`);
|
|
3986
4713
|
const res = await apiRequest3("GET", `/api/v1/developer/apps/${slug}/logs/${id}`);
|
|
3987
4714
|
if (!res.ok) {
|
|
@@ -3996,7 +4723,7 @@ async function logsGet(id, opts) {
|
|
|
3996
4723
|
}
|
|
3997
4724
|
}
|
|
3998
4725
|
async function logsTail(opts) {
|
|
3999
|
-
const slug =
|
|
4726
|
+
const slug = resolveSlug2(opts.app);
|
|
4000
4727
|
if (isJsonMode()) {
|
|
4001
4728
|
outputError("UNSUPPORTED", "Log tailing is not supported in JSON mode. Use `logs list` instead.");
|
|
4002
4729
|
}
|
|
@@ -4304,16 +5031,26 @@ function toPascalCase(s) {
|
|
|
4304
5031
|
|
|
4305
5032
|
// bin/bagdock.ts
|
|
4306
5033
|
init_output();
|
|
5034
|
+
init_config();
|
|
4307
5035
|
var program2 = new Command;
|
|
4308
|
-
program2.name("bagdock").description("Bagdock developer CLI").version("0.
|
|
5036
|
+
program2.name("bagdock").description("Bagdock developer CLI — built for humans, AI agents, and CI/CD pipelines").version("0.4.0").option("--json", "Force JSON output (auto-enabled in non-TTY)").option("-q, --quiet", "Suppress status messages (implies --json)").option("--api-key <key>", "API key to use for this invocation").option("-p, --profile <name>", "Profile to use (overrides BAGDOCK_PROFILE)").hook("preAction", (_thisCommand, actionCommand) => {
|
|
4309
5037
|
const opts = program2.opts();
|
|
4310
5038
|
setOutputMode({ json: opts.json, quiet: opts.quiet });
|
|
4311
5039
|
if (opts.apiKey)
|
|
4312
5040
|
setApiKeyOverride(opts.apiKey);
|
|
5041
|
+
if (opts.profile)
|
|
5042
|
+
setProfileOverride(opts.profile);
|
|
4313
5043
|
});
|
|
4314
5044
|
program2.command("login").description("Authenticate with Bagdock (opens browser)").action(login);
|
|
4315
5045
|
program2.command("logout").description("Clear stored credentials").action(logout);
|
|
4316
5046
|
program2.command("whoami").description("Show current authenticated user").action(whoami);
|
|
5047
|
+
var authCmd = program2.command("auth").description("Manage authentication profiles");
|
|
5048
|
+
authCmd.command("list").description("List all stored profiles").action(authList);
|
|
5049
|
+
authCmd.command("switch [name]").description("Switch active profile").action(async (name) => authSwitch(name));
|
|
5050
|
+
program2.command("doctor").description("Run environment diagnostics").action(async () => {
|
|
5051
|
+
const { doctor: doctor2 } = await Promise.resolve().then(() => (init_doctor(), exports_doctor));
|
|
5052
|
+
await doctor2();
|
|
5053
|
+
});
|
|
4317
5054
|
program2.command("init [dir]").description("Scaffold a new project with bagdock.json").option("-t, --type <type>", "Project type (edge, app)").option("-k, --kind <kind>", "Project kind (adapter, comms, webhook, ui-extension, microfrontend)").option("-c, --category <category>", "Category").option("-s, --slug <slug>", "Unique project slug").option("-n, --name <name>", "Display name").action((dir, opts) => init(dir ?? ".", opts));
|
|
4318
5055
|
program2.command("dev").description("Start local dev server").option("-p, --port <port>", "Local dev port", "8787").action(async (opts) => {
|
|
4319
5056
|
const { dev: dev2 } = await Promise.resolve().then(() => (init_dev(), exports_dev));
|
|
@@ -4327,6 +5064,35 @@ program2.command("submit").description("Submit app for Bagdock marketplace revie
|
|
|
4327
5064
|
const { submit: submit2 } = await Promise.resolve().then(() => (init_submit(), exports_submit));
|
|
4328
5065
|
await submit2();
|
|
4329
5066
|
});
|
|
5067
|
+
program2.command("validate").description("Run local pre-submission checks on bagdock.json and bundle").action(async () => {
|
|
5068
|
+
const { validate: validate2 } = await Promise.resolve().then(() => (init_validate(), exports_validate));
|
|
5069
|
+
await validate2();
|
|
5070
|
+
});
|
|
5071
|
+
var subCmd = program2.command("submission").description("Track marketplace submission status");
|
|
5072
|
+
subCmd.command("list").description("List submission history for the current app").option("--app <slug>", "App slug (defaults to bagdock.json or linked project)").action(async (opts) => {
|
|
5073
|
+
const { submissionList: submissionList2 } = await Promise.resolve().then(() => (init_submission(), exports_submission));
|
|
5074
|
+
await submissionList2(opts);
|
|
5075
|
+
});
|
|
5076
|
+
subCmd.command("status <id>").description("Fetch detailed review state for a submission").option("--app <slug>", "App slug").action(async (id, opts) => {
|
|
5077
|
+
const { submissionStatus: submissionStatus2 } = await Promise.resolve().then(() => (init_submission(), exports_submission));
|
|
5078
|
+
await submissionStatus2(id, opts);
|
|
5079
|
+
});
|
|
5080
|
+
subCmd.command("withdraw <id>").description("Cancel a pending submission before approval").option("--app <slug>", "App slug").action(async (id, opts) => {
|
|
5081
|
+
const { submissionWithdraw: submissionWithdraw2 } = await Promise.resolve().then(() => (init_submission(), exports_submission));
|
|
5082
|
+
await submissionWithdraw2(id, opts);
|
|
5083
|
+
});
|
|
5084
|
+
program2.command("open [slug]").description("Open project in the Bagdock dashboard").action(async (slug) => {
|
|
5085
|
+
const { open: open3 } = await Promise.resolve().then(() => (init_open2(), exports_open2));
|
|
5086
|
+
await open3(slug);
|
|
5087
|
+
});
|
|
5088
|
+
program2.command("inspect [slug]").description("Show deployment details and status for an app").action(async (slug) => {
|
|
5089
|
+
const { inspect: inspect2 } = await Promise.resolve().then(() => (init_inspect(), exports_inspect));
|
|
5090
|
+
await inspect2(slug);
|
|
5091
|
+
});
|
|
5092
|
+
program2.command("link").description("Link current directory to a Bagdock app or edge").option("--slug <slug>", "Project slug (required in non-interactive mode)").action(async (opts) => {
|
|
5093
|
+
const { link: link2 } = await Promise.resolve().then(() => (init_link(), exports_link));
|
|
5094
|
+
await link2(opts);
|
|
5095
|
+
});
|
|
4330
5096
|
var envCmd = program2.command("env").description("Manage app environment variables");
|
|
4331
5097
|
envCmd.command("list").description("List environment variables for this app").action(async () => {
|
|
4332
5098
|
const { envList: envList2 } = await Promise.resolve().then(() => (init_env_cmd(), exports_env_cmd));
|
|
@@ -4340,6 +5106,10 @@ envCmd.command("remove <key>").description("Remove an environment variable").act
|
|
|
4340
5106
|
const { envRemove: envRemove2 } = await Promise.resolve().then(() => (init_env_cmd(), exports_env_cmd));
|
|
4341
5107
|
await envRemove2(key);
|
|
4342
5108
|
});
|
|
5109
|
+
envCmd.command("pull [file]").description("Pull remote env var keys to a local .env file").action(async (file) => {
|
|
5110
|
+
const { envPull: envPull2 } = await Promise.resolve().then(() => (init_env_cmd(), exports_env_cmd));
|
|
5111
|
+
await envPull2(file);
|
|
5112
|
+
});
|
|
4343
5113
|
var keysCmd = program2.command("keys").description("Manage operator API keys");
|
|
4344
5114
|
keysCmd.command("create").description("Create a new API key (raw key shown once)").requiredOption("--name <name>", "Key name").option("--type <type>", "Key type (secret, publishable)", "secret").option("--category <category>", "Key category (standard, restricted, personal)", "standard").option("--environment <env>", "Environment (live, test)", "live").option("--scopes <scopes...>", "Permission scopes").action(async (opts) => {
|
|
4345
5115
|
const { keysCreate: keysCreate2 } = await Promise.resolve().then(() => (init_keys(), exports_keys));
|