@appfleet-cli/cli 0.1.1 → 0.1.3
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/dist/appfleet.js +386 -41
- package/dist/cloud-session.d.ts +1 -1
- package/dist/cloud-session.js +22 -11
- package/dist/command-registry.js +135 -25
- package/dist/local-vault.js +2 -1
- package/dist/project-memory.js +2 -1
- package/package.json +1 -1
package/dist/appfleet.js
CHANGED
|
@@ -3370,10 +3370,58 @@ var program = new Command();
|
|
|
3370
3370
|
|
|
3371
3371
|
// src/appfleet.ts
|
|
3372
3372
|
import { realpathSync } from "node:fs";
|
|
3373
|
+
import { readFile as readFile5 } from "node:fs/promises";
|
|
3374
|
+
import { dirname as dirname5, join as join4 } from "node:path";
|
|
3373
3375
|
import { fileURLToPath } from "node:url";
|
|
3374
3376
|
|
|
3375
3377
|
// src/command-registry.ts
|
|
3376
3378
|
var cliCommandDocs = [
|
|
3379
|
+
{
|
|
3380
|
+
namespace: "appfleet",
|
|
3381
|
+
name: "login",
|
|
3382
|
+
summary: "Sign in to AppFleet Cloud.",
|
|
3383
|
+
usage: "appfleet login [--workspace <workspace-id>] [--email <email>] [--api-base-url <url>] [--local-test] [--json]",
|
|
3384
|
+
arguments: [],
|
|
3385
|
+
options: [
|
|
3386
|
+
{ flags: "--workspace <workspace-id>", description: "Workspace id to sign in to; defaults to workspace_local." },
|
|
3387
|
+
{ flags: "--email <email>", description: "Optional non-secret user label for local-test identity metadata." },
|
|
3388
|
+
{ flags: "--api-base-url <url>", description: "AppFleet API base URL; overrides APPFLEET_API_BASE_URL and the default https://appfleet.xyz." },
|
|
3389
|
+
{ flags: "--local-test", description: "Create local-test session metadata instead of signing in to AppFleet Cloud." },
|
|
3390
|
+
{ flags: "--json", description: "Emit machine-readable JSON." }
|
|
3391
|
+
],
|
|
3392
|
+
examples: [
|
|
3393
|
+
"appfleet login",
|
|
3394
|
+
"appfleet login --workspace workspace_prod",
|
|
3395
|
+
"appfleet login --json"
|
|
3396
|
+
],
|
|
3397
|
+
reads: [".appfleet/cloud-session.json if it already exists"],
|
|
3398
|
+
writes: [".appfleet/cloud-session.json hosted redacted session metadata with status and expiry", ".appfleet/cloud-auth-token mode-0600 local credential file"],
|
|
3399
|
+
secretSafety: [
|
|
3400
|
+
"Opens the hosted browser auth flow and stores session metadata only.",
|
|
3401
|
+
"The short-lived hosted session token is isolated in a mode-0600 local credential file and is never printed or included in project memory.",
|
|
3402
|
+
"Does not store OAuth refresh material, session cookies, provider credentials, encrypted credential blobs, key wrappers, command output, secret fragments, or secret values."
|
|
3403
|
+
]
|
|
3404
|
+
},
|
|
3405
|
+
{
|
|
3406
|
+
namespace: "appfleet",
|
|
3407
|
+
name: "logout",
|
|
3408
|
+
summary: "Sign out of AppFleet Cloud.",
|
|
3409
|
+
usage: "appfleet logout [--api-base-url <url>] [--local-test] [--json]",
|
|
3410
|
+
arguments: [],
|
|
3411
|
+
options: [
|
|
3412
|
+
{ flags: "--api-base-url <url>", description: "AppFleet API base URL; overrides APPFLEET_API_BASE_URL and the default https://appfleet.xyz." },
|
|
3413
|
+
{ flags: "--local-test", description: "Remove local-test session metadata instead of revoking a hosted AppFleet Cloud session." },
|
|
3414
|
+
{ flags: "--json", description: "Emit machine-readable JSON." }
|
|
3415
|
+
],
|
|
3416
|
+
examples: ["appfleet logout", "appfleet logout --json"],
|
|
3417
|
+
reads: [".appfleet/cloud-session.json"],
|
|
3418
|
+
writes: [".appfleet/cloud-session.json and .appfleet/cloud-auth-token are removed when present"],
|
|
3419
|
+
secretSafety: [
|
|
3420
|
+
"Revokes hosted session metadata through AppFleet Cloud when available.",
|
|
3421
|
+
"Removes local hosted session metadata and the local credential file without printing credential material.",
|
|
3422
|
+
"Does not read or print OAuth refresh material, session cookies, provider credentials, encrypted credential blobs, key wrappers, command output, or secret fragments."
|
|
3423
|
+
]
|
|
3424
|
+
},
|
|
3377
3425
|
{
|
|
3378
3426
|
namespace: "appfleet",
|
|
3379
3427
|
name: "link",
|
|
@@ -3389,6 +3437,68 @@ var cliCommandDocs = [
|
|
|
3389
3437
|
"Never uploads environment values, credential values, command output, key wrappers, or provider payloads."
|
|
3390
3438
|
]
|
|
3391
3439
|
},
|
|
3440
|
+
{
|
|
3441
|
+
namespace: "appfleet",
|
|
3442
|
+
name: "doctor",
|
|
3443
|
+
summary: "Run safe diagnostics for a remembered project, optionally uploading the report.",
|
|
3444
|
+
usage: "appfleet doctor [project] [--upload] [--json]",
|
|
3445
|
+
arguments: ["project: project id, path, URL, or repo fingerprint; defaults to the current project when resolvable."],
|
|
3446
|
+
options: [
|
|
3447
|
+
{ flags: "--upload", description: "Upload the safe doctor report to AppFleet Cloud after the local check." },
|
|
3448
|
+
{ flags: "--json", description: "Emit machine-readable JSON." }
|
|
3449
|
+
],
|
|
3450
|
+
examples: [
|
|
3451
|
+
"appfleet doctor appfleet-demo",
|
|
3452
|
+
"appfleet doctor .",
|
|
3453
|
+
"appfleet doctor appfleet-demo --upload"
|
|
3454
|
+
],
|
|
3455
|
+
reads: [".appfleet/project-memory.json", ".appfleet/cloud-session.json when --upload is used"],
|
|
3456
|
+
writes: [".appfleet/project-memory.json latest safe doctor evidence", ".appfleet/cloud-metadata-sync.json when --upload is used"],
|
|
3457
|
+
secretSafety: [
|
|
3458
|
+
"Runs safe URL and metadata checks only.",
|
|
3459
|
+
"Uploads safe project metadata and doctor evidence only when --upload is passed.",
|
|
3460
|
+
"Never reads .env files or uploads environment values, credential values, command output, key wrappers, or provider payloads."
|
|
3461
|
+
]
|
|
3462
|
+
},
|
|
3463
|
+
{
|
|
3464
|
+
namespace: "appfleet",
|
|
3465
|
+
name: "workspaces",
|
|
3466
|
+
summary: "List AppFleet Cloud workspaces available to the signed-in user.",
|
|
3467
|
+
usage: "appfleet workspaces [--api-base-url <url>] [--json]",
|
|
3468
|
+
arguments: [],
|
|
3469
|
+
options: [
|
|
3470
|
+
{ flags: "--api-base-url <url>", description: "AppFleet API base URL; overrides APPFLEET_API_BASE_URL and the default https://appfleet.xyz." },
|
|
3471
|
+
{ flags: "--json", description: "Emit machine-readable JSON." }
|
|
3472
|
+
],
|
|
3473
|
+
examples: ["appfleet workspaces", "appfleet workspaces --json"],
|
|
3474
|
+
reads: [".appfleet/cloud-session.json", ".appfleet/cloud-auth-token"],
|
|
3475
|
+
writes: [],
|
|
3476
|
+
secretSafety: [
|
|
3477
|
+
"Uses the active hosted AppFleet session to list workspace metadata.",
|
|
3478
|
+
"Does not print auth tokens, cookies, provider credentials, environment values, or secret fragments."
|
|
3479
|
+
]
|
|
3480
|
+
},
|
|
3481
|
+
{
|
|
3482
|
+
namespace: "appfleet",
|
|
3483
|
+
name: "workspace",
|
|
3484
|
+
summary: "Show or change the active AppFleet Cloud workspace.",
|
|
3485
|
+
usage: "appfleet workspace current|list|use <workspace-id> [--json]",
|
|
3486
|
+
arguments: [],
|
|
3487
|
+
options: [
|
|
3488
|
+
{ flags: "--json", description: "Emit machine-readable JSON." }
|
|
3489
|
+
],
|
|
3490
|
+
examples: [
|
|
3491
|
+
"appfleet workspace current",
|
|
3492
|
+
"appfleet workspace list",
|
|
3493
|
+
"appfleet workspace use workspace_prod"
|
|
3494
|
+
],
|
|
3495
|
+
reads: [".appfleet/cloud-session.json", ".appfleet/cloud-auth-token"],
|
|
3496
|
+
writes: [".appfleet/cloud-session.json and .appfleet/cloud-auth-token when using a workspace"],
|
|
3497
|
+
secretSafety: [
|
|
3498
|
+
"Workspace use runs the hosted AppFleet login flow for the selected workspace.",
|
|
3499
|
+
"Stores active workspace session metadata only and never prints auth tokens, cookies, provider credentials, or secret fragments."
|
|
3500
|
+
]
|
|
3501
|
+
},
|
|
3392
3502
|
{
|
|
3393
3503
|
namespace: "appfleet",
|
|
3394
3504
|
name: "init",
|
|
@@ -3421,20 +3531,21 @@ var cliCommandDocs = [
|
|
|
3421
3531
|
{
|
|
3422
3532
|
namespace: "auth",
|
|
3423
3533
|
name: "login",
|
|
3424
|
-
summary: "
|
|
3425
|
-
usage: "appfleet auth login [--workspace <workspace-id>] [--email <email>] [--
|
|
3534
|
+
summary: "Sign in to AppFleet Cloud; use --local-test for local scaffold sessions.",
|
|
3535
|
+
usage: "appfleet auth login [--workspace <workspace-id>] [--email <email>] [--api-base-url <url>] [--local-test] [--json]",
|
|
3426
3536
|
arguments: [],
|
|
3427
3537
|
options: [
|
|
3428
3538
|
{ flags: "--workspace <workspace-id>", description: "Workspace id for local-test or hosted session metadata." },
|
|
3429
3539
|
{ flags: "--email <email>", description: "Optional non-secret user label for local-test identity or hosted login metadata." },
|
|
3430
|
-
{ flags: "--
|
|
3431
|
-
{ flags: "--
|
|
3540
|
+
{ flags: "--local-test", description: "Create local-test session metadata instead of signing in to AppFleet Cloud." },
|
|
3541
|
+
{ flags: "--production-cloud", description: "Deprecated compatibility flag; hosted AppFleet Cloud is already the default." },
|
|
3542
|
+
{ flags: "--api-base-url <url>", description: "Production AppFleet API base URL; overrides APPFLEET_API_BASE_URL and the default https://appfleet.xyz." },
|
|
3432
3543
|
{ flags: "--json", description: "Emit machine-readable JSON." }
|
|
3433
3544
|
],
|
|
3434
3545
|
examples: [
|
|
3435
|
-
"appfleet
|
|
3436
|
-
"appfleet auth login --workspace
|
|
3437
|
-
"
|
|
3546
|
+
"appfleet login",
|
|
3547
|
+
"appfleet auth login --workspace workspace_prod --json",
|
|
3548
|
+
"appfleet auth login --local-test --workspace workspace_test --email demo@example.com --json"
|
|
3438
3549
|
],
|
|
3439
3550
|
reads: [".appfleet/cloud-session.json if it already exists"],
|
|
3440
3551
|
writes: [".appfleet/cloud-session.json local-test or hosted redacted session metadata with status and expiry"],
|
|
@@ -3447,18 +3558,19 @@ var cliCommandDocs = [
|
|
|
3447
3558
|
{
|
|
3448
3559
|
namespace: "auth",
|
|
3449
3560
|
name: "logout",
|
|
3450
|
-
summary: "
|
|
3451
|
-
usage: "appfleet auth logout [--
|
|
3561
|
+
summary: "Sign out of AppFleet Cloud; use --local-test for local scaffold sessions.",
|
|
3562
|
+
usage: "appfleet auth logout [--api-base-url <url>] [--local-test] [--json]",
|
|
3452
3563
|
arguments: [],
|
|
3453
3564
|
options: [
|
|
3454
|
-
{ flags: "--
|
|
3455
|
-
{ flags: "--
|
|
3565
|
+
{ flags: "--local-test", description: "Remove local-test session metadata instead of revoking a hosted AppFleet Cloud session." },
|
|
3566
|
+
{ flags: "--production-cloud", description: "Deprecated compatibility flag; hosted AppFleet Cloud is already the default." },
|
|
3567
|
+
{ flags: "--api-base-url <url>", description: "Production AppFleet API base URL; overrides APPFLEET_API_BASE_URL and the default https://appfleet.xyz." },
|
|
3456
3568
|
{ flags: "--json", description: "Emit machine-readable JSON." }
|
|
3457
3569
|
],
|
|
3458
3570
|
examples: [
|
|
3459
|
-
"appfleet
|
|
3571
|
+
"appfleet logout",
|
|
3460
3572
|
"appfleet auth logout --json",
|
|
3461
|
-
"
|
|
3573
|
+
"appfleet auth logout --local-test --json"
|
|
3462
3574
|
],
|
|
3463
3575
|
reads: [".appfleet/cloud-session.json"],
|
|
3464
3576
|
writes: [".appfleet/cloud-session.json is removed when present; JSON output includes a safe logged_out/not_found/missing_hosted_session status"],
|
|
@@ -3476,23 +3588,23 @@ var cliCommandDocs = [
|
|
|
3476
3588
|
arguments: [],
|
|
3477
3589
|
options: [
|
|
3478
3590
|
{ flags: "--workspace <workspace-id>", description: "Workspace id for the local-test sync store." },
|
|
3479
|
-
{ flags: "--production-cloud", description: "Explicitly use production cloud mode
|
|
3480
|
-
{ flags: "--api-base-url <url>", description: "Production AppFleet API base URL; overrides APPFLEET_API_BASE_URL." },
|
|
3591
|
+
{ flags: "--production-cloud", description: "Explicitly use production cloud mode against AppFleet Cloud." },
|
|
3592
|
+
{ flags: "--api-base-url <url>", description: "Production AppFleet API base URL; overrides APPFLEET_API_BASE_URL and the default https://appfleet.xyz." },
|
|
3481
3593
|
{ flags: "--idempotency-key <key>", description: "Override the production metadata sync idempotency key; retries reuse the same key." },
|
|
3482
3594
|
{ flags: "--json", description: "Emit machine-readable JSON." }
|
|
3483
3595
|
],
|
|
3484
3596
|
examples: [
|
|
3485
3597
|
"appfleet cloud sync",
|
|
3486
3598
|
"appfleet cloud sync --workspace workspace_test --json",
|
|
3487
|
-
"APPFLEET_PRODUCTION_CLOUD_ENABLED=true
|
|
3488
|
-
"
|
|
3599
|
+
"APPFLEET_PRODUCTION_CLOUD_ENABLED=true APPFLEET_CLOUD_AUTH_TOKEN=<redacted> appfleet cloud sync --workspace <workspace-id> --json",
|
|
3600
|
+
"appfleet cloud sync --production-cloud --workspace <workspace-id> --json"
|
|
3489
3601
|
],
|
|
3490
3602
|
reads: [".appfleet/cloud-session.json", ".appfleet/project-memory.json", ".appfleet/cloud-metadata-sync.json"],
|
|
3491
3603
|
writes: [".appfleet/cloud-metadata-sync.json", ".appfleet/project-memory.json lastSyncedAt for accepted projects"],
|
|
3492
3604
|
secretSafety: [
|
|
3493
3605
|
"Chooses local-test mode by default; production mode requires --production-cloud, APPFLEET_PRODUCTION_CLOUD_ENABLED=true, or APPFLEET_CLOUD_MODE=production.",
|
|
3494
|
-
"In production mode, fails closed when
|
|
3495
|
-
"Production metadata sync posts to /api/workspaces/<workspace-id>/metadata-sync on the configured AppFleet web API base URL.",
|
|
3606
|
+
"In production mode, defaults to https://appfleet.xyz and fails closed when APPFLEET_CLOUD_AUTH_TOKEN is missing.",
|
|
3607
|
+
"Production metadata sync posts to /api/workspaces/<workspace-id>/metadata-sync on the configured or default AppFleet web API base URL.",
|
|
3496
3608
|
"Production metadata sync sends redacted auth reporting plus an idempotency key, workspace id, and project metadata envelopes.",
|
|
3497
3609
|
"Production metadata sync retries safe transient transport failures with the same idempotency key.",
|
|
3498
3610
|
"Persists local-test and production sync metadata, project ids, fingerprints, durable queue status, idempotency metadata, and conflict reports only.",
|
|
@@ -3508,23 +3620,23 @@ var cliCommandDocs = [
|
|
|
3508
3620
|
arguments: [],
|
|
3509
3621
|
options: [
|
|
3510
3622
|
{ flags: "--workspace <workspace-id>", description: "Workspace id for the local-test sync store." },
|
|
3511
|
-
{ flags: "--production-cloud", description: "Explicitly use production cloud mode
|
|
3512
|
-
{ flags: "--api-base-url <url>", description: "Production AppFleet API base URL; overrides APPFLEET_API_BASE_URL." },
|
|
3623
|
+
{ flags: "--production-cloud", description: "Explicitly use production cloud mode against AppFleet Cloud." },
|
|
3624
|
+
{ flags: "--api-base-url <url>", description: "Production AppFleet API base URL; overrides APPFLEET_API_BASE_URL and the default https://appfleet.xyz." },
|
|
3513
3625
|
{ flags: "--idempotency-key <key>", description: "Override the production metadata sync idempotency key; retries reuse the same key." },
|
|
3514
3626
|
{ flags: "--json", description: "Emit machine-readable JSON." }
|
|
3515
3627
|
],
|
|
3516
3628
|
examples: [
|
|
3517
3629
|
"appfleet cloud metadata-sync",
|
|
3518
3630
|
"appfleet cloud metadata-sync --workspace workspace_test --json",
|
|
3519
|
-
"APPFLEET_CLOUD_MODE=production
|
|
3520
|
-
"
|
|
3631
|
+
"APPFLEET_CLOUD_MODE=production APPFLEET_CLOUD_AUTH_TOKEN=<redacted> appfleet cloud metadata-sync --workspace <workspace-id> --json",
|
|
3632
|
+
"appfleet cloud metadata-sync --production-cloud --workspace <workspace-id> --json"
|
|
3521
3633
|
],
|
|
3522
3634
|
reads: [".appfleet/cloud-session.json", ".appfleet/project-memory.json", ".appfleet/cloud-metadata-sync.json"],
|
|
3523
3635
|
writes: [".appfleet/cloud-metadata-sync.json", ".appfleet/project-memory.json lastSyncedAt for accepted projects"],
|
|
3524
3636
|
secretSafety: [
|
|
3525
3637
|
"Chooses local-test mode by default; production mode requires --production-cloud, APPFLEET_PRODUCTION_CLOUD_ENABLED=true, or APPFLEET_CLOUD_MODE=production.",
|
|
3526
|
-
"In production mode, fails closed when
|
|
3527
|
-
"Production metadata sync posts to /api/workspaces/<workspace-id>/metadata-sync on the configured AppFleet web API base URL.",
|
|
3638
|
+
"In production mode, defaults to https://appfleet.xyz and fails closed when APPFLEET_CLOUD_AUTH_TOKEN is missing.",
|
|
3639
|
+
"Production metadata sync posts to /api/workspaces/<workspace-id>/metadata-sync on the configured or default AppFleet web API base URL.",
|
|
3528
3640
|
"Production metadata sync sends redacted auth reporting plus an idempotency key, workspace id, and project metadata envelopes.",
|
|
3529
3641
|
"Production metadata sync retries safe transient transport failures with the same idempotency key.",
|
|
3530
3642
|
"Persists local-test and production sync metadata, project ids, fingerprints, durable queue status, idempotency metadata, and conflict reports only.",
|
|
@@ -8093,7 +8205,7 @@ function defaultProjectMemoryStorePath(cwd) {
|
|
|
8093
8205
|
function errorMessage2(error) {
|
|
8094
8206
|
return error instanceof Error ? error.message : String(error);
|
|
8095
8207
|
}
|
|
8096
|
-
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
8208
|
+
if (import.meta.url.endsWith("/project-memory.ts") && import.meta.url === `file://${process.argv[1]}`) {
|
|
8097
8209
|
const result = await runProjectMemoryCommand(process.argv.slice(2), {
|
|
8098
8210
|
storePath: process.env.APPFLEET_PROJECT_MEMORY_STORE_PATH,
|
|
8099
8211
|
currentGitRemoteFingerprint: process.env.APPFLEET_GIT_REMOTE_FINGERPRINT
|
|
@@ -8104,6 +8216,7 @@ if (import.meta.url === `file://${process.argv[1]}`) {
|
|
|
8104
8216
|
}
|
|
8105
8217
|
|
|
8106
8218
|
// src/cloud-session.ts
|
|
8219
|
+
var DEFAULT_PRODUCTION_API_BASE_URL = "https://appfleet.xyz";
|
|
8107
8220
|
async function runCloudSessionCommand(argv, options = {}) {
|
|
8108
8221
|
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
8109
8222
|
let env = options.env ?? process.env;
|
|
@@ -8172,7 +8285,7 @@ async function runCloudSessionCommand(argv, options = {}) {
|
|
|
8172
8285
|
createdAt: createdAt3,
|
|
8173
8286
|
result: authResult
|
|
8174
8287
|
});
|
|
8175
|
-
const localAuthToken = authResult.
|
|
8288
|
+
const localAuthToken = authResult.sessionId ?? authResult.authToken;
|
|
8176
8289
|
if (localAuthToken) {
|
|
8177
8290
|
await writeAuthToken(authTokenPath, localAuthToken);
|
|
8178
8291
|
}
|
|
@@ -8792,7 +8905,7 @@ function parseCloudSessionCommand(argv, env) {
|
|
|
8792
8905
|
action,
|
|
8793
8906
|
workspaceId: readFlag4(normalizedArgv, "--workspace") ?? "workspace_local",
|
|
8794
8907
|
email: readFlag4(normalizedArgv, "--email"),
|
|
8795
|
-
productionCloud: cloudProductionFlag(normalizedArgv, env),
|
|
8908
|
+
productionCloud: cloudProductionFlag(normalizedArgv, env, true),
|
|
8796
8909
|
productionCloudSource: cloudProductionSource(normalizedArgv, env),
|
|
8797
8910
|
apiBaseUrl: readFlag4(normalizedArgv, "--api-base-url"),
|
|
8798
8911
|
outputFormat
|
|
@@ -8802,7 +8915,7 @@ function parseCloudSessionCommand(argv, env) {
|
|
|
8802
8915
|
return {
|
|
8803
8916
|
namespace,
|
|
8804
8917
|
action,
|
|
8805
|
-
productionCloud: cloudProductionFlag(normalizedArgv, env),
|
|
8918
|
+
productionCloud: cloudProductionFlag(normalizedArgv, env, true),
|
|
8806
8919
|
productionCloudSource: cloudProductionSource(normalizedArgv, env),
|
|
8807
8920
|
apiBaseUrl: readFlag4(normalizedArgv, "--api-base-url"),
|
|
8808
8921
|
outputFormat
|
|
@@ -9110,23 +9223,35 @@ function createZeroSecretBoundary() {
|
|
|
9110
9223
|
storesSecretFragments: false
|
|
9111
9224
|
};
|
|
9112
9225
|
}
|
|
9113
|
-
function cloudProductionFlag(argv, env) {
|
|
9226
|
+
function cloudProductionFlag(argv, env, defaultProduction = false) {
|
|
9227
|
+
if (hasFlag2(argv, "--local-test")) {
|
|
9228
|
+
return false;
|
|
9229
|
+
}
|
|
9114
9230
|
if (hasFlag2(argv, "--production-cloud")) {
|
|
9115
9231
|
return true;
|
|
9116
9232
|
}
|
|
9117
|
-
|
|
9233
|
+
if (env.APPFLEET_CLOUD_MODE === "local-test") {
|
|
9234
|
+
return false;
|
|
9235
|
+
}
|
|
9236
|
+
return env.APPFLEET_PRODUCTION_CLOUD_ENABLED === "true" || env.APPFLEET_CLOUD_MODE === "production" || defaultProduction;
|
|
9118
9237
|
}
|
|
9119
9238
|
function cloudProductionSource(argv, env) {
|
|
9239
|
+
if (hasFlag2(argv, "--local-test")) {
|
|
9240
|
+
return "flag";
|
|
9241
|
+
}
|
|
9120
9242
|
if (hasFlag2(argv, "--production-cloud")) {
|
|
9121
9243
|
return "flag";
|
|
9122
9244
|
}
|
|
9245
|
+
if (env.APPFLEET_CLOUD_MODE === "local-test") {
|
|
9246
|
+
return "env";
|
|
9247
|
+
}
|
|
9123
9248
|
if (productionEnvEnabled(env)) {
|
|
9124
9249
|
return "env";
|
|
9125
9250
|
}
|
|
9126
9251
|
return "default";
|
|
9127
9252
|
}
|
|
9128
9253
|
function resolveProductionCloudConfig(parsed, env) {
|
|
9129
|
-
const apiBaseUrl = parsed.apiBaseUrl ?? env.APPFLEET_API_BASE_URL;
|
|
9254
|
+
const apiBaseUrl = parsed.apiBaseUrl ?? env.APPFLEET_API_BASE_URL ?? DEFAULT_PRODUCTION_API_BASE_URL;
|
|
9130
9255
|
return {
|
|
9131
9256
|
enabled: parsed.productionCloud,
|
|
9132
9257
|
apiBaseUrl,
|
|
@@ -9134,7 +9259,7 @@ function resolveProductionCloudConfig(parsed, env) {
|
|
|
9134
9259
|
databaseDsn: env.APPFLEET_DATABASE_URL,
|
|
9135
9260
|
sources: {
|
|
9136
9261
|
enabled: parsed.productionCloudSource,
|
|
9137
|
-
apiBaseUrl: parsed.apiBaseUrl ? "flag" : env.APPFLEET_API_BASE_URL ? "env" : "
|
|
9262
|
+
apiBaseUrl: parsed.apiBaseUrl ? "flag" : env.APPFLEET_API_BASE_URL ? "env" : "default",
|
|
9138
9263
|
authToken: env.APPFLEET_CLOUD_AUTH_TOKEN ? env.APPFLEET_CLOUD_AUTH_TOKEN_SOURCE === "device_store" ? "device_store" : "env" : "missing",
|
|
9139
9264
|
databaseDsn: env.APPFLEET_DATABASE_URL ? "env" : "missing"
|
|
9140
9265
|
}
|
|
@@ -9145,14 +9270,11 @@ function productionEnvEnabled(env) {
|
|
|
9145
9270
|
}
|
|
9146
9271
|
function missingProductionConfig(config) {
|
|
9147
9272
|
return [
|
|
9148
|
-
config.apiBaseUrl ? void 0 : "APPFLEET_API_BASE_URL or --api-base-url",
|
|
9149
9273
|
config.authToken ? void 0 : "APPFLEET_CLOUD_AUTH_TOKEN"
|
|
9150
9274
|
].filter((value) => value !== void 0);
|
|
9151
9275
|
}
|
|
9152
9276
|
function missingProductionAuthConfig(config) {
|
|
9153
|
-
return [
|
|
9154
|
-
config.apiBaseUrl ? void 0 : "APPFLEET_API_BASE_URL or --api-base-url"
|
|
9155
|
-
].filter((value) => value !== void 0);
|
|
9277
|
+
return [];
|
|
9156
9278
|
}
|
|
9157
9279
|
function resolveHostedAuthTimeoutMs(env, override) {
|
|
9158
9280
|
const raw = override ?? Number.parseInt(env.APPFLEET_HOSTED_AUTH_TIMEOUT_MS ?? "", 10);
|
|
@@ -11461,7 +11583,7 @@ function commandError(error) {
|
|
|
11461
11583
|
childStarted: false
|
|
11462
11584
|
};
|
|
11463
11585
|
}
|
|
11464
|
-
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
11586
|
+
if (import.meta.url.endsWith("/local-vault.ts") && import.meta.url === `file://${process.argv[1]}`) {
|
|
11465
11587
|
const result = await runLocalVaultCommand(process.argv.slice(2));
|
|
11466
11588
|
process.stdout.write(result.stdout);
|
|
11467
11589
|
process.stderr.write(result.stderr);
|
|
@@ -11888,6 +12010,7 @@ var namespaces = [
|
|
|
11888
12010
|
"vault",
|
|
11889
12011
|
"secrets"
|
|
11890
12012
|
];
|
|
12013
|
+
var DEFAULT_PRODUCTION_API_BASE_URL2 = "https://appfleet.xyz";
|
|
11891
12014
|
async function runAppFleetCli(argv) {
|
|
11892
12015
|
const normalizedArgv = argv[0] === "--" ? argv.slice(1) : argv;
|
|
11893
12016
|
if (shouldShowHelp(normalizedArgv)) {
|
|
@@ -11901,6 +12024,61 @@ async function runAppFleetCli(argv) {
|
|
|
11901
12024
|
return 0;
|
|
11902
12025
|
}
|
|
11903
12026
|
const namespace = normalizedArgv[0];
|
|
12027
|
+
if (namespace === "login" || namespace === "logout") {
|
|
12028
|
+
const result = await runCloudSessionCommand(
|
|
12029
|
+
["auth", namespace, ...normalizedArgv.slice(1)],
|
|
12030
|
+
cloudCommandOptions()
|
|
12031
|
+
);
|
|
12032
|
+
process.stdout.write(result.stdout);
|
|
12033
|
+
process.stderr.write(result.stderr);
|
|
12034
|
+
return result.exitCode;
|
|
12035
|
+
}
|
|
12036
|
+
if (namespace === "workspaces") {
|
|
12037
|
+
const result = await runWorkspaceListCommand(normalizedArgv.slice(1));
|
|
12038
|
+
process.stdout.write(result.stdout);
|
|
12039
|
+
process.stderr.write(result.stderr);
|
|
12040
|
+
return result.exitCode;
|
|
12041
|
+
}
|
|
12042
|
+
if (namespace === "workspace") {
|
|
12043
|
+
const action = normalizedArgv[1] ?? "current";
|
|
12044
|
+
if (action === "use") {
|
|
12045
|
+
const workspaceId = normalizedArgv[2] ?? readFlag9(normalizedArgv, "--workspace");
|
|
12046
|
+
if (!workspaceId) {
|
|
12047
|
+
process.stderr.write("AppFleet workspace failed: usage: appfleet workspace use <workspace-id> [--json]\n");
|
|
12048
|
+
return 1;
|
|
12049
|
+
}
|
|
12050
|
+
const result = await runCloudSessionCommand(
|
|
12051
|
+
[
|
|
12052
|
+
"auth",
|
|
12053
|
+
"login",
|
|
12054
|
+
"--workspace",
|
|
12055
|
+
workspaceId,
|
|
12056
|
+
...normalizedArgv.includes("--json") ? ["--json"] : []
|
|
12057
|
+
],
|
|
12058
|
+
cloudCommandOptions()
|
|
12059
|
+
);
|
|
12060
|
+
process.stdout.write(result.stdout);
|
|
12061
|
+
process.stderr.write(result.stderr);
|
|
12062
|
+
return result.exitCode;
|
|
12063
|
+
}
|
|
12064
|
+
if (action === "current") {
|
|
12065
|
+
const result = await runWorkspaceCurrentCommand(normalizedArgv.slice(2));
|
|
12066
|
+
process.stdout.write(result.stdout);
|
|
12067
|
+
process.stderr.write(result.stderr);
|
|
12068
|
+
return result.exitCode;
|
|
12069
|
+
}
|
|
12070
|
+
if (action === "list") {
|
|
12071
|
+
const result = await runWorkspaceListCommand(normalizedArgv.slice(2));
|
|
12072
|
+
process.stdout.write(result.stdout);
|
|
12073
|
+
process.stderr.write(result.stderr);
|
|
12074
|
+
return result.exitCode;
|
|
12075
|
+
}
|
|
12076
|
+
process.stderr.write(
|
|
12077
|
+
`AppFleet workspace failed: unknown workspace command "${action}"
|
|
12078
|
+
`
|
|
12079
|
+
);
|
|
12080
|
+
return 1;
|
|
12081
|
+
}
|
|
11904
12082
|
if (namespace === "init") {
|
|
11905
12083
|
const result = await runFirstRunSetup(normalizedArgv.slice(1));
|
|
11906
12084
|
process.stdout.write(result.stdout);
|
|
@@ -11921,6 +12099,20 @@ async function runAppFleetCli(argv) {
|
|
|
11921
12099
|
process.stderr.write(result.stderr);
|
|
11922
12100
|
return result.exitCode;
|
|
11923
12101
|
}
|
|
12102
|
+
if (namespace === "doctor") {
|
|
12103
|
+
const args = ["projects", "doctor", ...normalizedArgv.slice(1)];
|
|
12104
|
+
if (normalizedArgv.includes("--upload")) {
|
|
12105
|
+
return runDoctorAndUpload(args);
|
|
12106
|
+
}
|
|
12107
|
+
const result = await runProjectMemoryCommand(args, {
|
|
12108
|
+
storePath: process.env.APPFLEET_PROJECT_MEMORY_STORE_PATH,
|
|
12109
|
+
currentGitRemoteFingerprint: process.env.APPFLEET_GIT_REMOTE_FINGERPRINT,
|
|
12110
|
+
projectRoot: process.env.INIT_CWD
|
|
12111
|
+
});
|
|
12112
|
+
process.stdout.write(result.stdout);
|
|
12113
|
+
process.stderr.write(result.stderr);
|
|
12114
|
+
return result.exitCode;
|
|
12115
|
+
}
|
|
11924
12116
|
if (namespace === "projects") {
|
|
11925
12117
|
if (normalizedArgv[1] === "doctor" && normalizedArgv.includes("--upload")) {
|
|
11926
12118
|
return runDoctorAndUpload(normalizedArgv);
|
|
@@ -11991,7 +12183,7 @@ async function runAppFleetCli(argv) {
|
|
|
11991
12183
|
}
|
|
11992
12184
|
function createAppFleetProgram() {
|
|
11993
12185
|
const program2 = new Command();
|
|
11994
|
-
program2.name("appfleet").description("
|
|
12186
|
+
program2.name("appfleet").description("AppFleet Cloud CLI for remembering, diagnosing, and recovering projects.").showHelpAfterError().configureHelp({ sortSubcommands: true, sortOptions: true });
|
|
11995
12187
|
const initDoc = findCliCommandDoc("appfleet", "init");
|
|
11996
12188
|
if (initDoc) {
|
|
11997
12189
|
program2.addCommand(commandFromDoc(initDoc));
|
|
@@ -12000,6 +12192,26 @@ function createAppFleetProgram() {
|
|
|
12000
12192
|
if (linkDoc) {
|
|
12001
12193
|
program2.addCommand(commandFromDoc(linkDoc));
|
|
12002
12194
|
}
|
|
12195
|
+
const loginDoc = findCliCommandDoc("appfleet", "login");
|
|
12196
|
+
if (loginDoc) {
|
|
12197
|
+
program2.addCommand(commandFromDoc(loginDoc));
|
|
12198
|
+
}
|
|
12199
|
+
const logoutDoc = findCliCommandDoc("appfleet", "logout");
|
|
12200
|
+
if (logoutDoc) {
|
|
12201
|
+
program2.addCommand(commandFromDoc(logoutDoc));
|
|
12202
|
+
}
|
|
12203
|
+
const doctorDoc = findCliCommandDoc("appfleet", "doctor");
|
|
12204
|
+
if (doctorDoc) {
|
|
12205
|
+
program2.addCommand(commandFromDoc(doctorDoc));
|
|
12206
|
+
}
|
|
12207
|
+
const workspacesDoc = findCliCommandDoc("appfleet", "workspaces");
|
|
12208
|
+
if (workspacesDoc) {
|
|
12209
|
+
program2.addCommand(commandFromDoc(workspacesDoc));
|
|
12210
|
+
}
|
|
12211
|
+
const workspaceDoc = findCliCommandDoc("appfleet", "workspace");
|
|
12212
|
+
if (workspaceDoc) {
|
|
12213
|
+
program2.addCommand(commandFromDoc(workspaceDoc));
|
|
12214
|
+
}
|
|
12003
12215
|
for (const namespace of namespaces) {
|
|
12004
12216
|
const namespaceCommand = new Command(namespace).description(
|
|
12005
12217
|
namespaceDescription(namespace)
|
|
@@ -12022,6 +12234,139 @@ function cloudCommandOptions() {
|
|
|
12022
12234
|
env: process.env
|
|
12023
12235
|
};
|
|
12024
12236
|
}
|
|
12237
|
+
async function runWorkspaceCurrentCommand(argv) {
|
|
12238
|
+
const outputFormat = argv.includes("--json") ? "json" : "human";
|
|
12239
|
+
const session = await readHostedSession();
|
|
12240
|
+
if (!session) {
|
|
12241
|
+
const document2 = {
|
|
12242
|
+
type: "appfleet_active_workspace_result",
|
|
12243
|
+
version: 1,
|
|
12244
|
+
status: "not_logged_in",
|
|
12245
|
+
activeWorkspaceId: void 0,
|
|
12246
|
+
next: "Run appfleet login."
|
|
12247
|
+
};
|
|
12248
|
+
return {
|
|
12249
|
+
exitCode: 1,
|
|
12250
|
+
stdout: outputFormat === "json" ? `${JSON.stringify(document2, null, 2)}
|
|
12251
|
+
` : "",
|
|
12252
|
+
stderr: outputFormat === "json" ? "" : "AppFleet workspace failed: not logged in. Run appfleet login.\n"
|
|
12253
|
+
};
|
|
12254
|
+
}
|
|
12255
|
+
const document = {
|
|
12256
|
+
type: "appfleet_active_workspace_result",
|
|
12257
|
+
version: 1,
|
|
12258
|
+
status: "ok",
|
|
12259
|
+
activeWorkspaceId: session.workspaceId,
|
|
12260
|
+
user: session.user,
|
|
12261
|
+
expiresAt: session.expiresAt
|
|
12262
|
+
};
|
|
12263
|
+
return {
|
|
12264
|
+
exitCode: 0,
|
|
12265
|
+
stdout: outputFormat === "json" ? `${JSON.stringify(document, null, 2)}
|
|
12266
|
+
` : `Active workspace: ${session.workspaceId}
|
|
12267
|
+
`,
|
|
12268
|
+
stderr: ""
|
|
12269
|
+
};
|
|
12270
|
+
}
|
|
12271
|
+
async function runWorkspaceListCommand(argv) {
|
|
12272
|
+
const outputFormat = argv.includes("--json") ? "json" : "human";
|
|
12273
|
+
const session = await readHostedSession();
|
|
12274
|
+
const authToken = await readWorkspaceAuthToken();
|
|
12275
|
+
if (!session || !authToken) {
|
|
12276
|
+
const document2 = {
|
|
12277
|
+
type: "appfleet_workspace_list_result",
|
|
12278
|
+
version: 1,
|
|
12279
|
+
status: "not_logged_in",
|
|
12280
|
+
workspaces: [],
|
|
12281
|
+
next: "Run appfleet login."
|
|
12282
|
+
};
|
|
12283
|
+
return {
|
|
12284
|
+
exitCode: 1,
|
|
12285
|
+
stdout: outputFormat === "json" ? `${JSON.stringify(document2, null, 2)}
|
|
12286
|
+
` : "",
|
|
12287
|
+
stderr: outputFormat === "json" ? "" : "AppFleet workspaces failed: not logged in. Run appfleet login.\n"
|
|
12288
|
+
};
|
|
12289
|
+
}
|
|
12290
|
+
const apiBaseUrl = readFlag9(argv, "--api-base-url") ?? process.env.APPFLEET_API_BASE_URL ?? DEFAULT_PRODUCTION_API_BASE_URL2;
|
|
12291
|
+
const url = new URL("/api/workspaces", apiBaseUrl);
|
|
12292
|
+
url.searchParams.set("workspaceId", session.workspaceId);
|
|
12293
|
+
const response = await fetch(url, {
|
|
12294
|
+
headers: {
|
|
12295
|
+
Accept: "application/json",
|
|
12296
|
+
"X-AppFleet-Hosted-Session": authToken,
|
|
12297
|
+
"X-AppFleet-Workspace-Id": session.workspaceId
|
|
12298
|
+
}
|
|
12299
|
+
});
|
|
12300
|
+
if (!response.ok) {
|
|
12301
|
+
const document2 = {
|
|
12302
|
+
type: "appfleet_workspace_list_result",
|
|
12303
|
+
version: 1,
|
|
12304
|
+
status: "request_failed",
|
|
12305
|
+
httpStatusCode: response.status,
|
|
12306
|
+
activeWorkspaceId: session.workspaceId,
|
|
12307
|
+
workspaces: []
|
|
12308
|
+
};
|
|
12309
|
+
return {
|
|
12310
|
+
exitCode: 1,
|
|
12311
|
+
stdout: outputFormat === "json" ? `${JSON.stringify(document2, null, 2)}
|
|
12312
|
+
` : "",
|
|
12313
|
+
stderr: outputFormat === "json" ? "" : `AppFleet workspaces failed: cloud request returned HTTP ${response.status}.
|
|
12314
|
+
`
|
|
12315
|
+
};
|
|
12316
|
+
}
|
|
12317
|
+
const parsed = await response.json();
|
|
12318
|
+
const workspaces = parsed.data?.workspaces ?? [];
|
|
12319
|
+
const document = {
|
|
12320
|
+
type: "appfleet_workspace_list_result",
|
|
12321
|
+
version: 1,
|
|
12322
|
+
status: "ok",
|
|
12323
|
+
activeWorkspaceId: session.workspaceId,
|
|
12324
|
+
workspaces: workspaces.map((workspace) => ({
|
|
12325
|
+
...workspace,
|
|
12326
|
+
active: workspace.id === session.workspaceId
|
|
12327
|
+
}))
|
|
12328
|
+
};
|
|
12329
|
+
return {
|
|
12330
|
+
exitCode: 0,
|
|
12331
|
+
stdout: outputFormat === "json" ? `${JSON.stringify(document, null, 2)}
|
|
12332
|
+
` : formatWorkspaceList(document),
|
|
12333
|
+
stderr: ""
|
|
12334
|
+
};
|
|
12335
|
+
}
|
|
12336
|
+
function formatWorkspaceList(document) {
|
|
12337
|
+
if (document.workspaces.length === 0) {
|
|
12338
|
+
return "No workspaces found.\n";
|
|
12339
|
+
}
|
|
12340
|
+
return `${document.workspaces.map(
|
|
12341
|
+
(workspace) => `${workspace.active ? "*" : " "} ${workspace.name} (${workspace.id})`
|
|
12342
|
+
).join("\n")}
|
|
12343
|
+
`;
|
|
12344
|
+
}
|
|
12345
|
+
async function readHostedSession() {
|
|
12346
|
+
try {
|
|
12347
|
+
const parsed = JSON.parse(await readFile5(defaultCliSessionPath(), "utf8"));
|
|
12348
|
+
if (!parsed.workspaceId) return void 0;
|
|
12349
|
+
return {
|
|
12350
|
+
type: parsed.type,
|
|
12351
|
+
workspaceId: parsed.workspaceId,
|
|
12352
|
+
user: parsed.user,
|
|
12353
|
+
expiresAt: parsed.expiresAt
|
|
12354
|
+
};
|
|
12355
|
+
} catch {
|
|
12356
|
+
return void 0;
|
|
12357
|
+
}
|
|
12358
|
+
}
|
|
12359
|
+
async function readWorkspaceAuthToken() {
|
|
12360
|
+
try {
|
|
12361
|
+
const token = await readFile5(join4(dirname5(defaultCliSessionPath()), "cloud-auth-token"), "utf8");
|
|
12362
|
+
return token.trim() || void 0;
|
|
12363
|
+
} catch {
|
|
12364
|
+
return void 0;
|
|
12365
|
+
}
|
|
12366
|
+
}
|
|
12367
|
+
function defaultCliSessionPath() {
|
|
12368
|
+
return process.env.APPFLEET_CLOUD_SESSION_PATH ?? join4(process.env.INIT_CWD ?? process.cwd(), ".appfleet", "cloud-session.json");
|
|
12369
|
+
}
|
|
12025
12370
|
async function runDoctorAndUpload(argv) {
|
|
12026
12371
|
const doctorArgs = argv.filter((argument) => argument !== "--upload");
|
|
12027
12372
|
if (!doctorArgs.includes("--json")) doctorArgs.push("--json");
|
|
@@ -12198,9 +12543,9 @@ function namespaceDescription(namespace) {
|
|
|
12198
12543
|
case "projects":
|
|
12199
12544
|
return "Remember projects, summarize recovery status, and run safe diagnostics.";
|
|
12200
12545
|
case "auth":
|
|
12201
|
-
return "Manage
|
|
12546
|
+
return "Manage AppFleet Cloud login sessions.";
|
|
12202
12547
|
case "cloud":
|
|
12203
|
-
return "
|
|
12548
|
+
return "Sync cloud-safe metadata with AppFleet Cloud.";
|
|
12204
12549
|
case "providers":
|
|
12205
12550
|
return "Inspect provider integration contracts and fail-closed discovery scaffolds.";
|
|
12206
12551
|
case "ops":
|
package/dist/cloud-session.d.ts
CHANGED
|
@@ -24,7 +24,7 @@ type ProductionCloudConfig = {
|
|
|
24
24
|
databaseDsn?: string;
|
|
25
25
|
sources: {
|
|
26
26
|
enabled: "flag" | "env" | "default";
|
|
27
|
-
apiBaseUrl: "flag" | "env" | "missing";
|
|
27
|
+
apiBaseUrl: "flag" | "env" | "default" | "missing";
|
|
28
28
|
authToken: "env" | "device_store" | "missing";
|
|
29
29
|
databaseDsn: "env" | "missing";
|
|
30
30
|
};
|
package/dist/cloud-session.js
CHANGED
|
@@ -5,6 +5,7 @@ import { dirname, join } from "node:path";
|
|
|
5
5
|
import { spawn } from "node:child_process";
|
|
6
6
|
import { createAppProjectMemory, createCloudSyncMetadata, createCloudSyncRuntimeConflictState, createLocalMetadataSyncQueueEntry, createProjectMemorySyncRequest, createProjectMemorySyncResult, } from "@appfleet/domain";
|
|
7
7
|
import { readProjectMemories, writeProjectMemories } from "./project-memory.js";
|
|
8
|
+
const DEFAULT_PRODUCTION_API_BASE_URL = "https://appfleet.xyz";
|
|
8
9
|
export async function runCloudSessionCommand(argv, options = {}) {
|
|
9
10
|
const now = options.now ?? (() => new Date());
|
|
10
11
|
let env = options.env ?? process.env;
|
|
@@ -72,7 +73,7 @@ export async function runCloudSessionCommand(argv, options = {}) {
|
|
|
72
73
|
createdAt,
|
|
73
74
|
result: authResult,
|
|
74
75
|
});
|
|
75
|
-
const localAuthToken = authResult.
|
|
76
|
+
const localAuthToken = authResult.sessionId ?? authResult.authToken;
|
|
76
77
|
if (localAuthToken) {
|
|
77
78
|
await writeAuthToken(authTokenPath, localAuthToken);
|
|
78
79
|
}
|
|
@@ -706,7 +707,7 @@ function parseCloudSessionCommand(argv, env) {
|
|
|
706
707
|
action,
|
|
707
708
|
workspaceId: readFlag(normalizedArgv, "--workspace") ?? "workspace_local",
|
|
708
709
|
email: readFlag(normalizedArgv, "--email"),
|
|
709
|
-
productionCloud: cloudProductionFlag(normalizedArgv, env),
|
|
710
|
+
productionCloud: cloudProductionFlag(normalizedArgv, env, true),
|
|
710
711
|
productionCloudSource: cloudProductionSource(normalizedArgv, env),
|
|
711
712
|
apiBaseUrl: readFlag(normalizedArgv, "--api-base-url"),
|
|
712
713
|
outputFormat,
|
|
@@ -716,7 +717,7 @@ function parseCloudSessionCommand(argv, env) {
|
|
|
716
717
|
return {
|
|
717
718
|
namespace,
|
|
718
719
|
action,
|
|
719
|
-
productionCloud: cloudProductionFlag(normalizedArgv, env),
|
|
720
|
+
productionCloud: cloudProductionFlag(normalizedArgv, env, true),
|
|
720
721
|
productionCloudSource: cloudProductionSource(normalizedArgv, env),
|
|
721
722
|
apiBaseUrl: readFlag(normalizedArgv, "--api-base-url"),
|
|
722
723
|
outputFormat,
|
|
@@ -1014,24 +1015,37 @@ function createZeroSecretBoundary() {
|
|
|
1014
1015
|
storesSecretFragments: false,
|
|
1015
1016
|
};
|
|
1016
1017
|
}
|
|
1017
|
-
function cloudProductionFlag(argv, env) {
|
|
1018
|
+
function cloudProductionFlag(argv, env, defaultProduction = false) {
|
|
1019
|
+
if (hasFlag(argv, "--local-test")) {
|
|
1020
|
+
return false;
|
|
1021
|
+
}
|
|
1018
1022
|
if (hasFlag(argv, "--production-cloud")) {
|
|
1019
1023
|
return true;
|
|
1020
1024
|
}
|
|
1025
|
+
if (env.APPFLEET_CLOUD_MODE === "local-test") {
|
|
1026
|
+
return false;
|
|
1027
|
+
}
|
|
1021
1028
|
return (env.APPFLEET_PRODUCTION_CLOUD_ENABLED === "true" ||
|
|
1022
|
-
env.APPFLEET_CLOUD_MODE === "production"
|
|
1029
|
+
env.APPFLEET_CLOUD_MODE === "production" ||
|
|
1030
|
+
defaultProduction);
|
|
1023
1031
|
}
|
|
1024
1032
|
function cloudProductionSource(argv, env) {
|
|
1033
|
+
if (hasFlag(argv, "--local-test")) {
|
|
1034
|
+
return "flag";
|
|
1035
|
+
}
|
|
1025
1036
|
if (hasFlag(argv, "--production-cloud")) {
|
|
1026
1037
|
return "flag";
|
|
1027
1038
|
}
|
|
1039
|
+
if (env.APPFLEET_CLOUD_MODE === "local-test") {
|
|
1040
|
+
return "env";
|
|
1041
|
+
}
|
|
1028
1042
|
if (productionEnvEnabled(env)) {
|
|
1029
1043
|
return "env";
|
|
1030
1044
|
}
|
|
1031
1045
|
return "default";
|
|
1032
1046
|
}
|
|
1033
1047
|
function resolveProductionCloudConfig(parsed, env) {
|
|
1034
|
-
const apiBaseUrl = parsed.apiBaseUrl ?? env.APPFLEET_API_BASE_URL;
|
|
1048
|
+
const apiBaseUrl = parsed.apiBaseUrl ?? env.APPFLEET_API_BASE_URL ?? DEFAULT_PRODUCTION_API_BASE_URL;
|
|
1035
1049
|
return {
|
|
1036
1050
|
enabled: parsed.productionCloud,
|
|
1037
1051
|
apiBaseUrl,
|
|
@@ -1043,7 +1057,7 @@ function resolveProductionCloudConfig(parsed, env) {
|
|
|
1043
1057
|
? "flag"
|
|
1044
1058
|
: env.APPFLEET_API_BASE_URL
|
|
1045
1059
|
? "env"
|
|
1046
|
-
: "
|
|
1060
|
+
: "default",
|
|
1047
1061
|
authToken: env.APPFLEET_CLOUD_AUTH_TOKEN
|
|
1048
1062
|
? env.APPFLEET_CLOUD_AUTH_TOKEN_SOURCE === "device_store"
|
|
1049
1063
|
? "device_store"
|
|
@@ -1059,14 +1073,11 @@ function productionEnvEnabled(env) {
|
|
|
1059
1073
|
}
|
|
1060
1074
|
function missingProductionConfig(config) {
|
|
1061
1075
|
return [
|
|
1062
|
-
config.apiBaseUrl ? undefined : "APPFLEET_API_BASE_URL or --api-base-url",
|
|
1063
1076
|
config.authToken ? undefined : "APPFLEET_CLOUD_AUTH_TOKEN",
|
|
1064
1077
|
].filter((value) => value !== undefined);
|
|
1065
1078
|
}
|
|
1066
1079
|
function missingProductionAuthConfig(config) {
|
|
1067
|
-
return [
|
|
1068
|
-
config.apiBaseUrl ? undefined : "APPFLEET_API_BASE_URL or --api-base-url",
|
|
1069
|
-
].filter((value) => value !== undefined);
|
|
1080
|
+
return [];
|
|
1070
1081
|
}
|
|
1071
1082
|
function resolveHostedAuthTimeoutMs(env, override) {
|
|
1072
1083
|
const raw = override ?? Number.parseInt(env.APPFLEET_HOSTED_AUTH_TIMEOUT_MS ?? "", 10);
|
package/dist/command-registry.js
CHANGED
|
@@ -1,4 +1,50 @@
|
|
|
1
1
|
export const cliCommandDocs = [
|
|
2
|
+
{
|
|
3
|
+
namespace: "appfleet",
|
|
4
|
+
name: "login",
|
|
5
|
+
summary: "Sign in to AppFleet Cloud.",
|
|
6
|
+
usage: "appfleet login [--workspace <workspace-id>] [--email <email>] [--api-base-url <url>] [--local-test] [--json]",
|
|
7
|
+
arguments: [],
|
|
8
|
+
options: [
|
|
9
|
+
{ flags: "--workspace <workspace-id>", description: "Workspace id to sign in to; defaults to workspace_local." },
|
|
10
|
+
{ flags: "--email <email>", description: "Optional non-secret user label for local-test identity metadata." },
|
|
11
|
+
{ flags: "--api-base-url <url>", description: "AppFleet API base URL; overrides APPFLEET_API_BASE_URL and the default https://appfleet.xyz." },
|
|
12
|
+
{ flags: "--local-test", description: "Create local-test session metadata instead of signing in to AppFleet Cloud." },
|
|
13
|
+
{ flags: "--json", description: "Emit machine-readable JSON." },
|
|
14
|
+
],
|
|
15
|
+
examples: [
|
|
16
|
+
"appfleet login",
|
|
17
|
+
"appfleet login --workspace workspace_prod",
|
|
18
|
+
"appfleet login --json",
|
|
19
|
+
],
|
|
20
|
+
reads: [".appfleet/cloud-session.json if it already exists"],
|
|
21
|
+
writes: [".appfleet/cloud-session.json hosted redacted session metadata with status and expiry", ".appfleet/cloud-auth-token mode-0600 local credential file"],
|
|
22
|
+
secretSafety: [
|
|
23
|
+
"Opens the hosted browser auth flow and stores session metadata only.",
|
|
24
|
+
"The short-lived hosted session token is isolated in a mode-0600 local credential file and is never printed or included in project memory.",
|
|
25
|
+
"Does not store OAuth refresh material, session cookies, provider credentials, encrypted credential blobs, key wrappers, command output, secret fragments, or secret values.",
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
namespace: "appfleet",
|
|
30
|
+
name: "logout",
|
|
31
|
+
summary: "Sign out of AppFleet Cloud.",
|
|
32
|
+
usage: "appfleet logout [--api-base-url <url>] [--local-test] [--json]",
|
|
33
|
+
arguments: [],
|
|
34
|
+
options: [
|
|
35
|
+
{ flags: "--api-base-url <url>", description: "AppFleet API base URL; overrides APPFLEET_API_BASE_URL and the default https://appfleet.xyz." },
|
|
36
|
+
{ flags: "--local-test", description: "Remove local-test session metadata instead of revoking a hosted AppFleet Cloud session." },
|
|
37
|
+
{ flags: "--json", description: "Emit machine-readable JSON." },
|
|
38
|
+
],
|
|
39
|
+
examples: ["appfleet logout", "appfleet logout --json"],
|
|
40
|
+
reads: [".appfleet/cloud-session.json"],
|
|
41
|
+
writes: [".appfleet/cloud-session.json and .appfleet/cloud-auth-token are removed when present"],
|
|
42
|
+
secretSafety: [
|
|
43
|
+
"Revokes hosted session metadata through AppFleet Cloud when available.",
|
|
44
|
+
"Removes local hosted session metadata and the local credential file without printing credential material.",
|
|
45
|
+
"Does not read or print OAuth refresh material, session cookies, provider credentials, encrypted credential blobs, key wrappers, command output, or secret fragments.",
|
|
46
|
+
],
|
|
47
|
+
},
|
|
2
48
|
{
|
|
3
49
|
namespace: "appfleet",
|
|
4
50
|
name: "link",
|
|
@@ -14,6 +60,68 @@ export const cliCommandDocs = [
|
|
|
14
60
|
"Never uploads environment values, credential values, command output, key wrappers, or provider payloads.",
|
|
15
61
|
],
|
|
16
62
|
},
|
|
63
|
+
{
|
|
64
|
+
namespace: "appfleet",
|
|
65
|
+
name: "doctor",
|
|
66
|
+
summary: "Run safe diagnostics for a remembered project, optionally uploading the report.",
|
|
67
|
+
usage: "appfleet doctor [project] [--upload] [--json]",
|
|
68
|
+
arguments: ["project: project id, path, URL, or repo fingerprint; defaults to the current project when resolvable."],
|
|
69
|
+
options: [
|
|
70
|
+
{ flags: "--upload", description: "Upload the safe doctor report to AppFleet Cloud after the local check." },
|
|
71
|
+
{ flags: "--json", description: "Emit machine-readable JSON." },
|
|
72
|
+
],
|
|
73
|
+
examples: [
|
|
74
|
+
"appfleet doctor appfleet-demo",
|
|
75
|
+
"appfleet doctor .",
|
|
76
|
+
"appfleet doctor appfleet-demo --upload",
|
|
77
|
+
],
|
|
78
|
+
reads: [".appfleet/project-memory.json", ".appfleet/cloud-session.json when --upload is used"],
|
|
79
|
+
writes: [".appfleet/project-memory.json latest safe doctor evidence", ".appfleet/cloud-metadata-sync.json when --upload is used"],
|
|
80
|
+
secretSafety: [
|
|
81
|
+
"Runs safe URL and metadata checks only.",
|
|
82
|
+
"Uploads safe project metadata and doctor evidence only when --upload is passed.",
|
|
83
|
+
"Never reads .env files or uploads environment values, credential values, command output, key wrappers, or provider payloads.",
|
|
84
|
+
],
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
namespace: "appfleet",
|
|
88
|
+
name: "workspaces",
|
|
89
|
+
summary: "List AppFleet Cloud workspaces available to the signed-in user.",
|
|
90
|
+
usage: "appfleet workspaces [--api-base-url <url>] [--json]",
|
|
91
|
+
arguments: [],
|
|
92
|
+
options: [
|
|
93
|
+
{ flags: "--api-base-url <url>", description: "AppFleet API base URL; overrides APPFLEET_API_BASE_URL and the default https://appfleet.xyz." },
|
|
94
|
+
{ flags: "--json", description: "Emit machine-readable JSON." },
|
|
95
|
+
],
|
|
96
|
+
examples: ["appfleet workspaces", "appfleet workspaces --json"],
|
|
97
|
+
reads: [".appfleet/cloud-session.json", ".appfleet/cloud-auth-token"],
|
|
98
|
+
writes: [],
|
|
99
|
+
secretSafety: [
|
|
100
|
+
"Uses the active hosted AppFleet session to list workspace metadata.",
|
|
101
|
+
"Does not print auth tokens, cookies, provider credentials, environment values, or secret fragments.",
|
|
102
|
+
],
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
namespace: "appfleet",
|
|
106
|
+
name: "workspace",
|
|
107
|
+
summary: "Show or change the active AppFleet Cloud workspace.",
|
|
108
|
+
usage: "appfleet workspace current|list|use <workspace-id> [--json]",
|
|
109
|
+
arguments: [],
|
|
110
|
+
options: [
|
|
111
|
+
{ flags: "--json", description: "Emit machine-readable JSON." },
|
|
112
|
+
],
|
|
113
|
+
examples: [
|
|
114
|
+
"appfleet workspace current",
|
|
115
|
+
"appfleet workspace list",
|
|
116
|
+
"appfleet workspace use workspace_prod",
|
|
117
|
+
],
|
|
118
|
+
reads: [".appfleet/cloud-session.json", ".appfleet/cloud-auth-token"],
|
|
119
|
+
writes: [".appfleet/cloud-session.json and .appfleet/cloud-auth-token when using a workspace"],
|
|
120
|
+
secretSafety: [
|
|
121
|
+
"Workspace use runs the hosted AppFleet login flow for the selected workspace.",
|
|
122
|
+
"Stores active workspace session metadata only and never prints auth tokens, cookies, provider credentials, or secret fragments.",
|
|
123
|
+
],
|
|
124
|
+
},
|
|
17
125
|
{
|
|
18
126
|
namespace: "appfleet",
|
|
19
127
|
name: "init",
|
|
@@ -46,20 +154,21 @@ export const cliCommandDocs = [
|
|
|
46
154
|
{
|
|
47
155
|
namespace: "auth",
|
|
48
156
|
name: "login",
|
|
49
|
-
summary: "
|
|
50
|
-
usage: "appfleet auth login [--workspace <workspace-id>] [--email <email>] [--
|
|
157
|
+
summary: "Sign in to AppFleet Cloud; use --local-test for local scaffold sessions.",
|
|
158
|
+
usage: "appfleet auth login [--workspace <workspace-id>] [--email <email>] [--api-base-url <url>] [--local-test] [--json]",
|
|
51
159
|
arguments: [],
|
|
52
160
|
options: [
|
|
53
161
|
{ flags: "--workspace <workspace-id>", description: "Workspace id for local-test or hosted session metadata." },
|
|
54
162
|
{ flags: "--email <email>", description: "Optional non-secret user label for local-test identity or hosted login metadata." },
|
|
55
|
-
{ flags: "--
|
|
56
|
-
{ flags: "--
|
|
163
|
+
{ flags: "--local-test", description: "Create local-test session metadata instead of signing in to AppFleet Cloud." },
|
|
164
|
+
{ flags: "--production-cloud", description: "Deprecated compatibility flag; hosted AppFleet Cloud is already the default." },
|
|
165
|
+
{ flags: "--api-base-url <url>", description: "Production AppFleet API base URL; overrides APPFLEET_API_BASE_URL and the default https://appfleet.xyz." },
|
|
57
166
|
{ flags: "--json", description: "Emit machine-readable JSON." },
|
|
58
167
|
],
|
|
59
168
|
examples: [
|
|
60
|
-
"appfleet
|
|
61
|
-
"appfleet auth login --workspace
|
|
62
|
-
"
|
|
169
|
+
"appfleet login",
|
|
170
|
+
"appfleet auth login --workspace workspace_prod --json",
|
|
171
|
+
"appfleet auth login --local-test --workspace workspace_test --email demo@example.com --json",
|
|
63
172
|
],
|
|
64
173
|
reads: [".appfleet/cloud-session.json if it already exists"],
|
|
65
174
|
writes: [".appfleet/cloud-session.json local-test or hosted redacted session metadata with status and expiry"],
|
|
@@ -72,18 +181,19 @@ export const cliCommandDocs = [
|
|
|
72
181
|
{
|
|
73
182
|
namespace: "auth",
|
|
74
183
|
name: "logout",
|
|
75
|
-
summary: "
|
|
76
|
-
usage: "appfleet auth logout [--
|
|
184
|
+
summary: "Sign out of AppFleet Cloud; use --local-test for local scaffold sessions.",
|
|
185
|
+
usage: "appfleet auth logout [--api-base-url <url>] [--local-test] [--json]",
|
|
77
186
|
arguments: [],
|
|
78
187
|
options: [
|
|
79
|
-
{ flags: "--
|
|
80
|
-
{ flags: "--
|
|
188
|
+
{ flags: "--local-test", description: "Remove local-test session metadata instead of revoking a hosted AppFleet Cloud session." },
|
|
189
|
+
{ flags: "--production-cloud", description: "Deprecated compatibility flag; hosted AppFleet Cloud is already the default." },
|
|
190
|
+
{ flags: "--api-base-url <url>", description: "Production AppFleet API base URL; overrides APPFLEET_API_BASE_URL and the default https://appfleet.xyz." },
|
|
81
191
|
{ flags: "--json", description: "Emit machine-readable JSON." },
|
|
82
192
|
],
|
|
83
193
|
examples: [
|
|
84
|
-
"appfleet
|
|
194
|
+
"appfleet logout",
|
|
85
195
|
"appfleet auth logout --json",
|
|
86
|
-
"
|
|
196
|
+
"appfleet auth logout --local-test --json",
|
|
87
197
|
],
|
|
88
198
|
reads: [".appfleet/cloud-session.json"],
|
|
89
199
|
writes: [".appfleet/cloud-session.json is removed when present; JSON output includes a safe logged_out/not_found/missing_hosted_session status"],
|
|
@@ -101,23 +211,23 @@ export const cliCommandDocs = [
|
|
|
101
211
|
arguments: [],
|
|
102
212
|
options: [
|
|
103
213
|
{ flags: "--workspace <workspace-id>", description: "Workspace id for the local-test sync store." },
|
|
104
|
-
{ flags: "--production-cloud", description: "Explicitly use production cloud mode
|
|
105
|
-
{ flags: "--api-base-url <url>", description: "Production AppFleet API base URL; overrides APPFLEET_API_BASE_URL." },
|
|
214
|
+
{ flags: "--production-cloud", description: "Explicitly use production cloud mode against AppFleet Cloud." },
|
|
215
|
+
{ flags: "--api-base-url <url>", description: "Production AppFleet API base URL; overrides APPFLEET_API_BASE_URL and the default https://appfleet.xyz." },
|
|
106
216
|
{ flags: "--idempotency-key <key>", description: "Override the production metadata sync idempotency key; retries reuse the same key." },
|
|
107
217
|
{ flags: "--json", description: "Emit machine-readable JSON." },
|
|
108
218
|
],
|
|
109
219
|
examples: [
|
|
110
220
|
"appfleet cloud sync",
|
|
111
221
|
"appfleet cloud sync --workspace workspace_test --json",
|
|
112
|
-
"APPFLEET_PRODUCTION_CLOUD_ENABLED=true
|
|
113
|
-
"
|
|
222
|
+
"APPFLEET_PRODUCTION_CLOUD_ENABLED=true APPFLEET_CLOUD_AUTH_TOKEN=<redacted> appfleet cloud sync --workspace <workspace-id> --json",
|
|
223
|
+
"appfleet cloud sync --production-cloud --workspace <workspace-id> --json",
|
|
114
224
|
],
|
|
115
225
|
reads: [".appfleet/cloud-session.json", ".appfleet/project-memory.json", ".appfleet/cloud-metadata-sync.json"],
|
|
116
226
|
writes: [".appfleet/cloud-metadata-sync.json", ".appfleet/project-memory.json lastSyncedAt for accepted projects"],
|
|
117
227
|
secretSafety: [
|
|
118
228
|
"Chooses local-test mode by default; production mode requires --production-cloud, APPFLEET_PRODUCTION_CLOUD_ENABLED=true, or APPFLEET_CLOUD_MODE=production.",
|
|
119
|
-
"In production mode, fails closed when
|
|
120
|
-
"Production metadata sync posts to /api/workspaces/<workspace-id>/metadata-sync on the configured AppFleet web API base URL.",
|
|
229
|
+
"In production mode, defaults to https://appfleet.xyz and fails closed when APPFLEET_CLOUD_AUTH_TOKEN is missing.",
|
|
230
|
+
"Production metadata sync posts to /api/workspaces/<workspace-id>/metadata-sync on the configured or default AppFleet web API base URL.",
|
|
121
231
|
"Production metadata sync sends redacted auth reporting plus an idempotency key, workspace id, and project metadata envelopes.",
|
|
122
232
|
"Production metadata sync retries safe transient transport failures with the same idempotency key.",
|
|
123
233
|
"Persists local-test and production sync metadata, project ids, fingerprints, durable queue status, idempotency metadata, and conflict reports only.",
|
|
@@ -133,23 +243,23 @@ export const cliCommandDocs = [
|
|
|
133
243
|
arguments: [],
|
|
134
244
|
options: [
|
|
135
245
|
{ flags: "--workspace <workspace-id>", description: "Workspace id for the local-test sync store." },
|
|
136
|
-
{ flags: "--production-cloud", description: "Explicitly use production cloud mode
|
|
137
|
-
{ flags: "--api-base-url <url>", description: "Production AppFleet API base URL; overrides APPFLEET_API_BASE_URL." },
|
|
246
|
+
{ flags: "--production-cloud", description: "Explicitly use production cloud mode against AppFleet Cloud." },
|
|
247
|
+
{ flags: "--api-base-url <url>", description: "Production AppFleet API base URL; overrides APPFLEET_API_BASE_URL and the default https://appfleet.xyz." },
|
|
138
248
|
{ flags: "--idempotency-key <key>", description: "Override the production metadata sync idempotency key; retries reuse the same key." },
|
|
139
249
|
{ flags: "--json", description: "Emit machine-readable JSON." },
|
|
140
250
|
],
|
|
141
251
|
examples: [
|
|
142
252
|
"appfleet cloud metadata-sync",
|
|
143
253
|
"appfleet cloud metadata-sync --workspace workspace_test --json",
|
|
144
|
-
"APPFLEET_CLOUD_MODE=production
|
|
145
|
-
"
|
|
254
|
+
"APPFLEET_CLOUD_MODE=production APPFLEET_CLOUD_AUTH_TOKEN=<redacted> appfleet cloud metadata-sync --workspace <workspace-id> --json",
|
|
255
|
+
"appfleet cloud metadata-sync --production-cloud --workspace <workspace-id> --json",
|
|
146
256
|
],
|
|
147
257
|
reads: [".appfleet/cloud-session.json", ".appfleet/project-memory.json", ".appfleet/cloud-metadata-sync.json"],
|
|
148
258
|
writes: [".appfleet/cloud-metadata-sync.json", ".appfleet/project-memory.json lastSyncedAt for accepted projects"],
|
|
149
259
|
secretSafety: [
|
|
150
260
|
"Chooses local-test mode by default; production mode requires --production-cloud, APPFLEET_PRODUCTION_CLOUD_ENABLED=true, or APPFLEET_CLOUD_MODE=production.",
|
|
151
|
-
"In production mode, fails closed when
|
|
152
|
-
"Production metadata sync posts to /api/workspaces/<workspace-id>/metadata-sync on the configured AppFleet web API base URL.",
|
|
261
|
+
"In production mode, defaults to https://appfleet.xyz and fails closed when APPFLEET_CLOUD_AUTH_TOKEN is missing.",
|
|
262
|
+
"Production metadata sync posts to /api/workspaces/<workspace-id>/metadata-sync on the configured or default AppFleet web API base URL.",
|
|
153
263
|
"Production metadata sync sends redacted auth reporting plus an idempotency key, workspace id, and project metadata envelopes.",
|
|
154
264
|
"Production metadata sync retries safe transient transport failures with the same idempotency key.",
|
|
155
265
|
"Persists local-test and production sync metadata, project ids, fingerprints, durable queue status, idempotency metadata, and conflict reports only.",
|
package/dist/local-vault.js
CHANGED
|
@@ -1161,7 +1161,8 @@ function commandError(error) {
|
|
|
1161
1161
|
childStarted: false,
|
|
1162
1162
|
};
|
|
1163
1163
|
}
|
|
1164
|
-
if (import.meta.url
|
|
1164
|
+
if (import.meta.url.endsWith("/local-vault.ts") &&
|
|
1165
|
+
import.meta.url === `file://${process.argv[1]}`) {
|
|
1165
1166
|
const result = await runLocalVaultCommand(process.argv.slice(2));
|
|
1166
1167
|
process.stdout.write(result.stdout);
|
|
1167
1168
|
process.stderr.write(result.stderr);
|
package/dist/project-memory.js
CHANGED
|
@@ -1518,7 +1518,8 @@ function defaultProjectMemoryStorePath(cwd) {
|
|
|
1518
1518
|
function errorMessage(error) {
|
|
1519
1519
|
return error instanceof Error ? error.message : String(error);
|
|
1520
1520
|
}
|
|
1521
|
-
if (import.meta.url
|
|
1521
|
+
if (import.meta.url.endsWith("/project-memory.ts") &&
|
|
1522
|
+
import.meta.url === `file://${process.argv[1]}`) {
|
|
1522
1523
|
const result = await runProjectMemoryCommand(process.argv.slice(2), {
|
|
1523
1524
|
storePath: process.env.APPFLEET_PROJECT_MEMORY_STORE_PATH,
|
|
1524
1525
|
currentGitRemoteFingerprint: process.env.APPFLEET_GIT_REMOTE_FINGERPRINT,
|