archive-labs 1.0.4 → 1.0.6

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/LICENSE CHANGED
@@ -1,17 +1,17 @@
1
- Apache License
2
- Version 2.0, January 2004
3
- https://www.apache.org/licenses/
4
-
5
- Copyright 2026 Archive Labs
6
-
7
- Licensed under the Apache License, Version 2.0 (the "License");
8
- you may not use this file except in compliance with the License.
9
- You may obtain a copy of the License at
10
-
11
- https://www.apache.org/licenses/LICENSE-2.0
12
-
13
- Unless required by applicable law or agreed to in writing, software
14
- distributed under the License is distributed on an "AS IS" BASIS,
15
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
- See the License for the specific language governing permissions and
17
- limitations under the License.
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ https://www.apache.org/licenses/
4
+
5
+ Copyright 2026 Archive Labs
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ https://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
package/README.md CHANGED
@@ -1,75 +1,87 @@
1
- # Archive Labs CLI
2
-
3
- <p align="center">
4
- <img src="./logo.png" alt="Archive Labs" width="96" />
5
- </p>
6
-
7
- Archive Labs CLI is a terminal client for Archive. It signs in, inspects repository state, runs sync and readiness checks, and returns text or JSON output for scripts.
8
-
9
- ## Install
10
-
11
- ```bash
12
- npm install -g archive-labs
13
- archive
14
- ```
15
-
16
- No global install:
17
-
18
- ```bash
19
- npx archive-labs
20
- ```
21
-
22
- ## Commands
23
-
24
- Use these commands for common tasks:
25
-
26
- ```bash
27
- archive login
28
- archive status
29
- archive sync
30
- archive check pr 182 --repository acme/payments --ci --json --strict
31
- archive impact diff --json
32
- archive release risk v1.2.0
33
- ```
34
-
35
- Command summary:
36
-
37
- ```bash
38
- archive init Set default API and app targets for the workspace.
39
- archive login Sign in and store credentials for later commands.
40
- archive status Show repository health, readiness, and missing signals.
41
- archive sync Refresh the repository index and derived metadata.
42
- archive check Run the default readiness or local change check.
43
- archive check pr <number> Evaluate a pull request for merge readiness.
44
- archive check diff Evaluate the current working tree before commit or push.
45
- archive impact file <path> Show what a file change affects.
46
- archive impact diff Summarize the impact of the current working tree.
47
- archive release summarize <tag> Summarize a release tag.
48
- archive release risk <tag> Review release risk before shipping.
49
- archive recent Show recently used CLI commands.
50
- archive doctor Inspect local config, auth, and runtime state.
51
- archive ping Check API connectivity.
52
- archive help Show the command list.
53
- archive version Print the installed CLI version.
54
- ```
55
-
56
- ## Output
57
-
58
- Use `--json` when you need machine-readable output. Text output is kept short and terminal-friendly.
59
-
60
- ## Config
61
-
62
- CLI config is stored under `~/.archive-labs/config.json`.
63
-
64
- Environment variables:
65
-
66
- - `ARCHIVE_TOKEN`
67
- - `ARCHIVE_LABS_TOKEN`
68
- - `ARCHIVE_GITHUB_TOKEN`
69
-
70
- ## Publish
71
-
72
- ```bash
73
- npm pack
74
- npm publish
75
- ```
1
+ # Archive Labs CLI
2
+
3
+ <p align="center">
4
+ <img src="https://cdn.jsdelivr.net/npm/archive-labs/logo.png" alt="Archive Labs" width="96" />
5
+ </p>
6
+
7
+ Archive Labs CLI is a terminal client for Archive. It signs in, reads repository state, runs sync and checks, and supports text or JSON output.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm install -g archive-labs
13
+ archive
14
+ ```
15
+
16
+ No global install:
17
+
18
+ ```bash
19
+ npx archive-labs
20
+ ```
21
+
22
+ ## Commands
23
+
24
+ ### Auth and setup
25
+
26
+ - `archive init` Set the API and app targets for this workspace.
27
+ - `archive login` Sign in and store credentials for later commands.
28
+ - `archive auth login` Alias for browser-based sign-in from onboarding flows.
29
+ - `archive logout` Remove stored credentials from this machine.
30
+
31
+ ### Repository checks
32
+
33
+ - `archive status` Show repository health, readiness, and missing signals.
34
+ - `archive sync` Refresh the repository index and derived metadata.
35
+ - `archive check` Run the default check for the current context.
36
+ - `archive check pr <number>` Review a pull request for merge readiness, impact, ownership, and blockers.
37
+ - `archive check diff` Review the current working tree before commit or push.
38
+ - `archive events` Review recent repository events.
39
+ - `archive recent` Show recently used commands.
40
+
41
+ ### Impact and release
42
+
43
+ - `archive impact file <path>` Show what a file change affects across services and downstream paths.
44
+ - `archive impact diff` Summarize the impact of the current working tree.
45
+ - `archive release summarize <tag>` Summarize what is included in a release tag.
46
+ - `archive release risk <tag>` Review release risk before shipping.
47
+ - `archive ask <question>` Query the codebase in natural language.
48
+ - `archive why <path>` Show file or folder context from history and evidence.
49
+
50
+ ### Utilities
51
+
52
+ - `archive doctor` Inspect local config, auth, and runtime state.
53
+ - `archive ping` Check API connectivity.
54
+ - `archive help` Show the command list and usage.
55
+ - `archive version` Print the installed CLI version.
56
+
57
+ Example usage:
58
+
59
+ ```bash
60
+ archive login
61
+ archive status
62
+ archive sync
63
+ archive check pr 182 --repository acme/payments --ci --json --strict
64
+ archive impact diff --json
65
+ archive release risk v1.2.0
66
+ ```
67
+
68
+ ## Output
69
+
70
+ Use `--json` when you need machine-readable output. Text output stays short and terminal-friendly.
71
+
72
+ ## Config
73
+
74
+ CLI config is stored under `~/.archive-labs/config.json`.
75
+
76
+ Environment variables:
77
+
78
+ - `ARCHIVE_TOKEN`
79
+ - `ARCHIVE_LABS_TOKEN`
80
+ - `ARCHIVE_GITHUB_TOKEN`
81
+
82
+ ## Publish
83
+
84
+ ```bash
85
+ npm pack
86
+ npm publish
87
+ ```
package/dist/cli.js CHANGED
@@ -52,6 +52,7 @@ const systemCheckStaleSyncThresholdMs = 72 * 60 * 60 * 1000;
52
52
  const impactPollIntervalMs = 1500;
53
53
  const defaultApiUrl = "https://api.archivelabs.dev";
54
54
  const defaultAppUrl = "https://app.archivelabs.dev";
55
+ const defaultLocalAppUrl = "http://localhost:8080";
55
56
  const legacyApiUrl = "http://localhost:3000";
56
57
  const legacyAppUrl = "http://localhost:5173";
57
58
  const jsonSchemaVersion = 1;
@@ -170,6 +171,10 @@ const utilityHelpEntries = [
170
171
  command: "archive login",
171
172
  description: "Authenticate with GitHub, Google, Microsoft, or email.",
172
173
  },
174
+ {
175
+ command: "archive auth login",
176
+ description: "Alias for archive login; opens browser sign-in.",
177
+ },
173
178
  {
174
179
  command: "archive logout",
175
180
  description: "Remove stored Archive login credentials from this machine.",
@@ -423,6 +428,19 @@ const matchesNormalizedUrl = (value, expected) => {
423
428
  return false;
424
429
  }
425
430
  };
431
+ const isLocalhostUrl = (value) => {
432
+ if (!value?.trim()) {
433
+ return false;
434
+ }
435
+ try {
436
+ const parsed = new URL(normalizeBaseUrl(value));
437
+ const hostname = parsed.hostname.toLowerCase();
438
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname === "[::1]";
439
+ }
440
+ catch {
441
+ return false;
442
+ }
443
+ };
426
444
  const renderLocalInitFixCommand = () => `${primaryCommand} init --api-url ${defaultApiUrl} --app-url ${defaultAppUrl} -y`;
427
445
  const getLegacyConfigWarnings = (config) => {
428
446
  const warnings = [];
@@ -471,9 +489,12 @@ const joinCommandInput = (value, label) => {
471
489
  return normalized;
472
490
  };
473
491
  let repoEnvPromise = null;
492
+ const repoEnvFileNames = [".env", ".env.local", ".env.development", ".env.development.local"];
474
493
  const getRepoEnvPaths = () => [
475
- path.join(process.cwd(), ".env"),
476
- path.join(process.cwd(), "backend", ".env"),
494
+ ...repoEnvFileNames.map((fileName) => path.join(process.cwd(), fileName)),
495
+ ...repoEnvFileNames.map((fileName) => path.join(process.cwd(), "backend", fileName)),
496
+ ...repoEnvFileNames.map((fileName) => path.join(process.cwd(), "apps", "backend", fileName)),
497
+ ...repoEnvFileNames.map((fileName) => path.join(process.cwd(), "apps", "frontend", fileName)),
477
498
  ];
478
499
  const readRepoEnv = async () => {
479
500
  if (!repoEnvPromise) {
@@ -501,7 +522,7 @@ const resolveBaseUrl = (explicit, config) => {
501
522
  return normalizeBaseUrl(config.apiUrl);
502
523
  return defaultApiUrl;
503
524
  };
504
- const resolveAppUrl = async (explicit, config) => {
525
+ const resolveAppUrl = async (explicit, config, apiUrl) => {
505
526
  if (explicit?.trim())
506
527
  return normalizeBaseUrl(explicit);
507
528
  if (process.env.ARCHIVE_LABS_APP_URL?.trim()) {
@@ -524,6 +545,9 @@ const resolveAppUrl = async (explicit, config) => {
524
545
  if (repoCandidate?.trim()) {
525
546
  return normalizeBaseUrl(repoCandidate);
526
547
  }
548
+ if (isLocalhostUrl(apiUrl)) {
549
+ return defaultLocalAppUrl;
550
+ }
527
551
  return defaultAppUrl;
528
552
  };
529
553
  const resolveHealthUrl = (explicit, config) => {
@@ -1670,7 +1694,7 @@ const serializeSummaryAction = (action) => action?.kind === "command"
1670
1694
  : null;
1671
1695
  const buildSetupReadinessSummary = async (config) => {
1672
1696
  const accessContext = await loadRepositoryAccessContext(config);
1673
- const appUrl = await resolveAppUrl(undefined, config);
1697
+ const appUrl = await resolveAppUrl(undefined, config, resolveBaseUrl(undefined, config));
1674
1698
  const selectionPlan = planRepositorySelection({
1675
1699
  canPrompt: false,
1676
1700
  explicitRepositoryFullName: null,
@@ -5977,7 +6001,7 @@ const createCliCallbackServer = async (expectedState, allowedOrigin, apiUrl) =>
5977
6001
  };
5978
6002
  const runOAuthLogin = async (provider, options, existingConfig) => {
5979
6003
  const apiUrl = resolveBaseUrl(options.apiUrl, existingConfig);
5980
- const appUrl = await resolveAppUrl(options.appUrl, existingConfig);
6004
+ const appUrl = await resolveAppUrl(options.appUrl, existingConfig, apiUrl);
5981
6005
  const state = crypto.randomBytes(20).toString("hex");
5982
6006
  const callbackServer = await createCliCallbackServer(state, new URL(appUrl).origin, apiUrl);
5983
6007
  const loginUrl = new URL("/auth", `${appUrl}/`);
@@ -6241,7 +6265,6 @@ const runInit = async (options = {}) => {
6241
6265
  clack.intro(`${primaryCommand} init`);
6242
6266
  }
6243
6267
  const resolvedApiUrl = resolveBaseUrl(undefined, existingConfig);
6244
- const resolvedAppUrl = await resolveAppUrl(undefined, existingConfig);
6245
6268
  let apiUrl = options.apiUrl?.trim() || (options.yes ? resolvedApiUrl : "");
6246
6269
  if (!apiUrl) {
6247
6270
  if (!allowPrompts) {
@@ -6273,6 +6296,7 @@ const runInit = async (options = {}) => {
6273
6296
  apiUrl = String(response);
6274
6297
  }
6275
6298
  const normalizedApiUrl = normalizeBaseUrl(apiUrl);
6299
+ const resolvedAppUrl = await resolveAppUrl(undefined, existingConfig, normalizedApiUrl);
6276
6300
  let appUrl = options.appUrl?.trim() || (options.yes ? resolvedAppUrl : "");
6277
6301
  if (!appUrl) {
6278
6302
  if (!allowPrompts) {
@@ -6391,7 +6415,7 @@ const runDoctor = async (options = {}) => {
6391
6415
  {
6392
6416
  title: "Resolve app target",
6393
6417
  task: async () => {
6394
- appUrl = await resolveAppUrl(undefined, config);
6418
+ appUrl = await resolveAppUrl(undefined, config, apiBaseUrl);
6395
6419
  },
6396
6420
  },
6397
6421
  ], {
@@ -6723,7 +6747,7 @@ const runSync = async (options = {}) => {
6723
6747
  const repositoryState = getSyncRepositoryState(repository);
6724
6748
  const lastIndexedAt = repository.lastSyncedAt ?? null;
6725
6749
  if (!repository.appInstalled || !repository.installationId) {
6726
- const appUrl = await resolveAppUrl(undefined, nextConfig);
6750
+ const appUrl = await resolveAppUrl(undefined, nextConfig, resolveBaseUrl(undefined, nextConfig));
6727
6751
  throw createSyncCliError({
6728
6752
  code: "app_install_required",
6729
6753
  hint: `${appUrl}/dashboard?flow=setup&provider=github`,
@@ -8643,6 +8667,42 @@ const buildProgram = async () => {
8643
8667
  .action(withCommandHandling("archive release risk", async (tag, options) => {
8644
8668
  await runReleaseRisk(tag, options);
8645
8669
  }));
8670
+ const authCommand = program
8671
+ .command("auth")
8672
+ .description("Manage Archive authentication");
8673
+ authCommand.helpInformation = () => renderGroupHelp(version, "Auth", [
8674
+ {
8675
+ command: "archive auth login",
8676
+ description: "Authenticate with GitHub, Google, Microsoft, or email.",
8677
+ },
8678
+ {
8679
+ command: "archive auth logout",
8680
+ description: "Remove stored Archive login credentials from this machine.",
8681
+ },
8682
+ ]);
8683
+ authCommand.action(withCommandHandling("archive auth", async () => {
8684
+ authCommand.outputHelp();
8685
+ }));
8686
+ authCommand
8687
+ .command("login")
8688
+ .description("Sign in with GitHub, Google, Microsoft, or email")
8689
+ .option("--provider <provider>", "Login method (github, google, azure, microsoft, or email)", parseLoginProvider)
8690
+ .option("--email <email>", "Email address for email login")
8691
+ .option("--api-url <url>", "Archive Labs API URL for email login")
8692
+ .option("--app-url <url>", "Archive Labs app URL for browser login")
8693
+ .option("--json", "Output login state as JSON")
8694
+ .option("--timeout <ms>", "Login timeout in milliseconds", parseTimeout, defaultLoginTimeoutMs)
8695
+ .option("--no-browser", "Print the browser sign-in URL instead of opening it automatically")
8696
+ .action(withCommandHandling("archive auth login", async (options) => {
8697
+ await runLogin(options);
8698
+ }));
8699
+ authCommand
8700
+ .command("logout")
8701
+ .description("Remove stored Archive login credentials from this machine")
8702
+ .option("--json", "Output logout state as JSON")
8703
+ .action(withCommandHandling("archive auth logout", async (options) => {
8704
+ await runLogout(options);
8705
+ }));
8646
8706
  program
8647
8707
  .command("login")
8648
8708
  .description("Sign in with GitHub, Google, Microsoft, or email")
@@ -99,6 +99,9 @@ export const inferCommandGroup = (argv) => {
99
99
  if (head === "release") {
100
100
  return "release";
101
101
  }
102
+ if (head === "auth" && (next === "login" || next === "logout")) {
103
+ return "utility";
104
+ }
102
105
  if (head === "login" || head === "doctor" || head === "ping" || head === "help" || head === "version" || head === "recent") {
103
106
  return "utility";
104
107
  }
package/package.json CHANGED
@@ -1,56 +1,56 @@
1
- {
2
- "name": "archive-labs",
3
- "version": "1.0.4",
4
- "description": "Terminal client for Archive that handles login, repo status, sync, checks, impact, and release risk.",
5
- "license": "Apache-2.0",
6
- "preferGlobal": true,
7
- "packageManager": "pnpm@10.33.0",
8
- "type": "module",
9
- "bin": {
10
- "archive": "./dist/cli.js",
11
- "archive-labs": "./dist/cli.js"
12
- },
13
- "files": [
14
- "dist",
15
- "logo.png",
16
- "README.md",
17
- "LICENSE"
18
- ],
19
- "engines": {
20
- "node": ">=22.13.0"
21
- },
22
- "scripts": {
23
- "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
24
- "build": "tsc -p tsconfig.json",
25
- "dev": "tsx watch src/cli.ts",
26
- "start": "node dist/cli.js",
27
- "smoke": "node dist/cli.js version && node dist/cli.js help",
28
- "pack:verify": "node scripts/verify-pack.mjs",
29
- "test:contract": "node scripts/test-contract.mjs",
30
- "lint": "npm run typecheck",
31
- "typecheck": "tsc -p tsconfig.json --noEmit",
32
- "test:integration": "npm run build && node scripts/run-node-tests.mjs",
33
- "test": "npm run test:integration",
34
- "ci": "npm run clean && npm run typecheck && npm run build && npm run smoke && npm run test",
35
- "prepack": "npm run build",
36
- "prepublishOnly": "npm run ci && npm run pack:verify"
37
- },
38
- "keywords": [
39
- "archive-labs",
40
- "archive",
41
- "cli"
42
- ],
43
- "devDependencies": {
44
- "@types/node": "^22.16.5",
45
- "tsx": "^4.20.3",
46
- "typescript": "^5.9.3"
47
- },
48
- "dependencies": {
49
- "@clack/prompts": "^1.2.0",
50
- "@napi-rs/keyring": "^1.3.0",
51
- "chalk": "^5.6.2",
52
- "commander": "^14.0.3",
53
- "listr2": "^10.2.1",
54
- "ora": "^9.3.0"
55
- }
56
- }
1
+ {
2
+ "name": "archive-labs",
3
+ "version": "1.0.6",
4
+ "description": "Terminal CLI for Archive that manages login, repository status, sync, checks, impact analysis, and release risk.",
5
+ "license": "Apache-2.0",
6
+ "preferGlobal": true,
7
+ "packageManager": "pnpm@10.33.0",
8
+ "type": "module",
9
+ "bin": {
10
+ "archive": "./dist/cli.js",
11
+ "archive-labs": "./dist/cli.js"
12
+ },
13
+ "files": [
14
+ "dist",
15
+ "logo.png",
16
+ "README.md",
17
+ "LICENSE"
18
+ ],
19
+ "engines": {
20
+ "node": ">=22.13.0"
21
+ },
22
+ "scripts": {
23
+ "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
24
+ "build": "tsc -p tsconfig.json",
25
+ "dev": "tsx watch src/cli.ts",
26
+ "start": "node dist/cli.js",
27
+ "smoke": "node dist/cli.js version && node dist/cli.js help",
28
+ "pack:verify": "node scripts/verify-pack.mjs",
29
+ "test:contract": "node scripts/test-contract.mjs",
30
+ "lint": "npm run typecheck",
31
+ "typecheck": "tsc -p tsconfig.json --noEmit",
32
+ "test:integration": "npm run build && node scripts/run-node-tests.mjs",
33
+ "test": "npm run test:integration",
34
+ "ci": "npm run clean && npm run typecheck && npm run build && npm run smoke && npm run test",
35
+ "prepack": "npm run build",
36
+ "prepublishOnly": "npm run ci && npm run pack:verify"
37
+ },
38
+ "keywords": [
39
+ "archive-labs",
40
+ "archive",
41
+ "cli"
42
+ ],
43
+ "devDependencies": {
44
+ "@types/node": "^22.16.5",
45
+ "tsx": "^4.20.3",
46
+ "typescript": "^5.9.3"
47
+ },
48
+ "dependencies": {
49
+ "@clack/prompts": "^1.2.0",
50
+ "@napi-rs/keyring": "^1.3.0",
51
+ "chalk": "^5.6.2",
52
+ "commander": "^14.0.3",
53
+ "listr2": "^10.2.1",
54
+ "ora": "^9.3.0"
55
+ }
56
+ }