archondev 2.1.4 → 2.2.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 CHANGED
@@ -53,6 +53,8 @@ Copy governance files into any project. Works with your existing AI tools: **Cur
53
53
  |---------|-------------|
54
54
  | `archon` | Interactive mode — just run and follow prompts |
55
55
  | `archon init` | Initialize in your project |
56
+ | `archon login` | Authenticate with ArchonDev (tier selection on first login) |
57
+ | `archon pricing` | View and switch pricing tiers (Free, BYOK, Credits) |
56
58
  | `archon plan <description>` | Create a work item with AI planning (extracts and confirms multi-item requests) |
57
59
  | `archon execute <atom-id>` | Execute with quality gates |
58
60
  | `archon list` | List all work items |
@@ -2,9 +2,10 @@ import {
2
2
  login,
3
3
  logout,
4
4
  status
5
- } from "./chunk-UI4UQ24R.js";
5
+ } from "./chunk-2BPIPDFV.js";
6
+ import "./chunk-C5TDNTNC.js";
6
7
  import "./chunk-M4LGRTLC.js";
7
- import "./chunk-IVY5AHPS.js";
8
+ import "./chunk-Y7DQ5XTU.js";
8
9
  import "./chunk-QGM4M3NI.js";
9
10
  export {
10
11
  login,
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  bugReport
3
- } from "./chunk-KF6MFAB4.js";
3
+ } from "./chunk-GLBVZOBA.js";
4
4
  import "./chunk-5IQKC2TD.js";
5
5
  import "./chunk-A7QU6JC6.js";
6
- import "./chunk-IVY5AHPS.js";
6
+ import "./chunk-Y7DQ5XTU.js";
7
7
  import "./chunk-QGM4M3NI.js";
8
8
  export {
9
9
  bugReport
@@ -1,3 +1,8 @@
1
+ import {
2
+ handleTierSetup,
3
+ promptTierSelection,
4
+ updateUserTier
5
+ } from "./chunk-C5TDNTNC.js";
1
6
  import {
2
7
  SUPABASE_ANON_KEY,
3
8
  SUPABASE_URL
@@ -6,7 +11,7 @@ import {
6
11
  clearConfig,
7
12
  loadConfig,
8
13
  saveConfig
9
- } from "./chunk-IVY5AHPS.js";
14
+ } from "./chunk-Y7DQ5XTU.js";
10
15
 
11
16
  // src/cli/auth.ts
12
17
  import { createClient } from "@supabase/supabase-js";
@@ -54,11 +59,15 @@ async function login(provider = "github") {
54
59
  }
55
60
  if (sessionData.session) {
56
61
  let userTier = "FREE";
62
+ let isFirstTimeUser = true;
57
63
  try {
58
- const { data: profileData } = await supabase.from("user_profiles").select("tier").eq("auth_id", sessionData.user.id).single();
59
- const profile = profileData;
60
- if (profile?.tier) {
61
- userTier = profile.tier;
64
+ const { data: profileData, error: profileError } = await supabase.from("user_profiles").select("tier").eq("auth_id", sessionData.user.id).single();
65
+ if (!profileError && profileData) {
66
+ const profile = profileData;
67
+ if (profile?.tier) {
68
+ userTier = profile.tier;
69
+ isFirstTimeUser = false;
70
+ }
62
71
  }
63
72
  } catch {
64
73
  }
@@ -71,7 +80,24 @@ async function login(provider = "github") {
71
80
  expiresAt: new Date(sessionData.session.expires_at ?? Date.now() + 36e5).toISOString()
72
81
  });
73
82
  spinner.succeed(chalk.green(`Logged in as ${sessionData.user.email}`));
74
- console.log(chalk.dim(`Tier: ${userTier}`));
83
+ if (isFirstTimeUser) {
84
+ const selection = await promptTierSelection();
85
+ if (selection && !selection.skipped) {
86
+ const updateResult = await updateUserTier(selection.tier);
87
+ if (updateResult.success) {
88
+ userTier = selection.tier;
89
+ console.log(chalk.green(`
90
+ \u2713 Tier set to ${formatTier(userTier)}`));
91
+ await handleTierSetup(selection.tier);
92
+ }
93
+ } else if (selection?.skipped) {
94
+ userTier = "FREE";
95
+ }
96
+ const config = await loadConfig();
97
+ await saveConfig({ ...config, tier: userTier });
98
+ } else {
99
+ console.log(chalk.dim(`Tier: ${formatTier(userTier)}`));
100
+ }
75
101
  }
76
102
  }
77
103
  } catch (error) {
@@ -3,16 +3,16 @@ import {
3
3
  createAtom,
4
4
  validateAtom
5
5
  } from "./chunk-5IQKC2TD.js";
6
+ import {
7
+ KeyManager
8
+ } from "./chunk-SMR7JQK6.js";
6
9
  import {
7
10
  AnthropicClient,
8
11
  getDefaultModel
9
12
  } from "./chunk-A7QU6JC6.js";
10
- import {
11
- KeyManager
12
- } from "./chunk-SMR7JQK6.js";
13
13
  import {
14
14
  isAuthenticated
15
- } from "./chunk-IVY5AHPS.js";
15
+ } from "./chunk-Y7DQ5XTU.js";
16
16
  import {
17
17
  ArchitectureParser
18
18
  } from "./chunk-5EVHUDQX.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  listLocalAtoms
3
- } from "./chunk-RCW22YNI.js";
3
+ } from "./chunk-5HVYNCLT.js";
4
4
 
5
5
  // src/cli/list.ts
6
6
  import chalk from "chalk";
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  loadConfig,
7
7
  saveConfig
8
- } from "./chunk-IVY5AHPS.js";
8
+ } from "./chunk-Y7DQ5XTU.js";
9
9
 
10
10
  // src/cli/keys.ts
11
11
  import chalk from "chalk";
@@ -0,0 +1,265 @@
1
+ import {
2
+ API_URL
3
+ } from "./chunk-M4LGRTLC.js";
4
+ import {
5
+ getApiUrl,
6
+ loadConfig,
7
+ saveConfig
8
+ } from "./chunk-Y7DQ5XTU.js";
9
+
10
+ // src/cli/tier-selection.ts
11
+ import chalk from "chalk";
12
+ import readline from "readline";
13
+ import ora from "ora";
14
+ import open from "open";
15
+ var TIER_INFO = {
16
+ FREE: {
17
+ name: "Free",
18
+ tagline: "Get started at no cost",
19
+ description: "Use ultra-cheap AI models (GPT-5-nano, Gemini Flash-Lite)",
20
+ limits: "Limited to $1/day, $5/month in AI usage",
21
+ models: "Basic models only",
22
+ cost: "$0"
23
+ },
24
+ BYOK: {
25
+ name: "BYOK (Bring Your Own Key)",
26
+ tagline: "Use your own API keys",
27
+ description: "Connect your Anthropic, OpenAI, or Google API keys",
28
+ limits: "Unlimited usage (you pay providers directly)",
29
+ models: "All models available",
30
+ cost: "$0 to ArchonDev"
31
+ },
32
+ CREDITS: {
33
+ name: "Credits",
34
+ tagline: "Pay-as-you-go with all models",
35
+ description: "We handle API access. Pay only for what you use.",
36
+ limits: "Unlimited usage",
37
+ models: "All models available (Claude, GPT-4, Gemini Pro, etc.)",
38
+ cost: "10% service fee on AI costs"
39
+ }
40
+ };
41
+ async function promptTierSelection() {
42
+ console.log();
43
+ console.log(chalk.bold("\u{1F389} Welcome to ArchonDev!"));
44
+ console.log();
45
+ console.log(chalk.dim("Choose how you want to use AI models:"));
46
+ console.log();
47
+ console.log(` ${chalk.cyan("1")}) ${chalk.bold(TIER_INFO.FREE.name)}`);
48
+ console.log(chalk.dim(` ${TIER_INFO.FREE.description}`));
49
+ console.log(chalk.dim(` ${TIER_INFO.FREE.limits}`));
50
+ console.log();
51
+ console.log(` ${chalk.cyan("2")}) ${chalk.bold(TIER_INFO.BYOK.name)}`);
52
+ console.log(chalk.dim(` ${TIER_INFO.BYOK.description}`));
53
+ console.log(chalk.green(` \u2713 ${TIER_INFO.BYOK.models}`));
54
+ console.log();
55
+ console.log(` ${chalk.cyan("3")}) ${chalk.bold(TIER_INFO.CREDITS.name)}`);
56
+ console.log(chalk.dim(` ${TIER_INFO.CREDITS.description}`));
57
+ console.log(chalk.green(` \u2713 ${TIER_INFO.CREDITS.models}`));
58
+ console.log(chalk.dim(` ${TIER_INFO.CREDITS.cost}`));
59
+ console.log();
60
+ console.log(` ${chalk.dim("s")}) ${chalk.dim("Skip for now (defaults to Free)")}`);
61
+ console.log();
62
+ const choice = await prompt("Enter choice (1-3 or s)");
63
+ switch (choice.toLowerCase()) {
64
+ case "1":
65
+ return { tier: "FREE", skipped: false };
66
+ case "2":
67
+ return { tier: "BYOK", skipped: false };
68
+ case "3":
69
+ return { tier: "CREDITS", skipped: false };
70
+ case "s":
71
+ case "skip":
72
+ case "":
73
+ console.log(chalk.dim("\nDefaulting to Free tier. You can change this anytime with `archon pricing`"));
74
+ return { tier: "FREE", skipped: true };
75
+ default:
76
+ console.log(chalk.yellow("Invalid choice. Defaulting to Free tier."));
77
+ return { tier: "FREE", skipped: true };
78
+ }
79
+ }
80
+ async function handleTierSetup(tier) {
81
+ const result = {};
82
+ if (tier === "CREDITS") {
83
+ const addCredits = await promptYesNo(
84
+ "Would you like to add credits now? (minimum $5)",
85
+ true
86
+ );
87
+ if (addCredits) {
88
+ const checkoutUrl = await createCheckoutSession(500);
89
+ if (checkoutUrl) {
90
+ result.checkoutUrl = checkoutUrl;
91
+ console.log();
92
+ console.log(chalk.green("Opening checkout in browser..."));
93
+ try {
94
+ await open(checkoutUrl);
95
+ } catch {
96
+ console.log(chalk.dim(`Visit: ${checkoutUrl}`));
97
+ }
98
+ }
99
+ } else {
100
+ console.log(chalk.dim("\nYou can add credits later with `archon credits add`"));
101
+ }
102
+ }
103
+ if (tier === "BYOK") {
104
+ console.log();
105
+ console.log(chalk.blue("Next step: Add your API keys"));
106
+ console.log(chalk.dim("Run one of these commands:"));
107
+ console.log(chalk.dim(" archon keys add anthropic"));
108
+ console.log(chalk.dim(" archon keys add openai"));
109
+ console.log(chalk.dim(" archon keys add google"));
110
+ }
111
+ return result;
112
+ }
113
+ async function createCheckoutSession(amountCents) {
114
+ const spinner = ora("Preparing checkout...").start();
115
+ try {
116
+ const config = await loadConfig();
117
+ if (!config.accessToken || !config.userId) {
118
+ spinner.fail("Not logged in");
119
+ return null;
120
+ }
121
+ const response = await fetch(`${API_URL}/api/checkout`, {
122
+ method: "POST",
123
+ headers: {
124
+ "Content-Type": "application/json",
125
+ "Authorization": `Bearer ${config.accessToken}`
126
+ },
127
+ body: JSON.stringify({
128
+ userId: config.userId,
129
+ amountCents
130
+ })
131
+ });
132
+ const result = await response.json();
133
+ if (!response.ok || !result.success) {
134
+ spinner.fail(result.error?.error || "Failed to create checkout");
135
+ return null;
136
+ }
137
+ spinner.succeed("Checkout ready");
138
+ return result.data?.checkoutUrl || null;
139
+ } catch (err) {
140
+ spinner.fail("Error creating checkout");
141
+ return null;
142
+ }
143
+ }
144
+ async function showTierSwitchMenu() {
145
+ const config = await loadConfig();
146
+ const currentTier = config.tier || "FREE";
147
+ console.log();
148
+ console.log(chalk.bold("Pricing & Billing"));
149
+ console.log();
150
+ console.log(`Current tier: ${formatTierDisplay(currentTier)}`);
151
+ console.log();
152
+ console.log(chalk.dim("Choose a pricing model:\n"));
153
+ const tiers = [
154
+ { key: "1", tier: "FREE", info: TIER_INFO.FREE },
155
+ { key: "2", tier: "BYOK", info: TIER_INFO.BYOK },
156
+ { key: "3", tier: "CREDITS", info: TIER_INFO.CREDITS }
157
+ ];
158
+ for (const { key, tier, info } of tiers) {
159
+ const isCurrent = tier === currentTier;
160
+ const marker = isCurrent ? chalk.green("\u25CF ") : "\u25CB ";
161
+ console.log(` ${chalk.cyan(key)}) ${marker}${chalk.bold(info.name)}`);
162
+ console.log(chalk.dim(` ${info.description}`));
163
+ if (tier !== "FREE") {
164
+ console.log(chalk.green(` \u2713 ${info.models}`));
165
+ }
166
+ console.log();
167
+ }
168
+ console.log(` ${chalk.dim("b")}) Back`);
169
+ console.log();
170
+ const choice = await prompt("Enter choice");
171
+ if (choice.toLowerCase() === "b" || choice === "") {
172
+ return;
173
+ }
174
+ const selected = tiers.find((t) => t.key === choice);
175
+ if (!selected) {
176
+ console.log(chalk.yellow("Invalid choice."));
177
+ return;
178
+ }
179
+ if (selected.tier === currentTier) {
180
+ console.log(chalk.dim("Already using this pricing model."));
181
+ return;
182
+ }
183
+ const spinner = ora(`Switching to ${selected.info.name}...`).start();
184
+ const result = await updateUserTier(selected.tier);
185
+ if (result.success) {
186
+ spinner.succeed(chalk.green(`Switched to ${selected.info.name}`));
187
+ await handleTierSetup(selected.tier);
188
+ } else {
189
+ spinner.fail(chalk.red(result.error || "Failed to update tier"));
190
+ }
191
+ }
192
+ async function updateUserTier(tier) {
193
+ try {
194
+ const config = await loadConfig();
195
+ if (!config.accessToken) {
196
+ return { success: false, error: "Not logged in" };
197
+ }
198
+ const apiUrl = getApiUrl(config);
199
+ const response = await fetch(`${apiUrl}/api/preferences`, {
200
+ method: "PATCH",
201
+ headers: {
202
+ "Authorization": `Bearer ${config.accessToken}`,
203
+ "Content-Type": "application/json"
204
+ },
205
+ body: JSON.stringify({ tier })
206
+ });
207
+ if (!response.ok) {
208
+ const text = await response.text();
209
+ return { success: false, error: text };
210
+ }
211
+ await saveConfig({ ...config, tier });
212
+ return { success: true };
213
+ } catch (err) {
214
+ const message = err instanceof Error ? err.message : "Unknown error";
215
+ return { success: false, error: message };
216
+ }
217
+ }
218
+ function formatTierDisplay(tier) {
219
+ switch (tier) {
220
+ case "FREE":
221
+ return chalk.gray("Free");
222
+ case "CREDITS":
223
+ return chalk.green("Credits (Pay-as-you-go)");
224
+ case "BYOK":
225
+ return chalk.blue("BYOK (Bring Your Own Key)");
226
+ default:
227
+ return tier;
228
+ }
229
+ }
230
+ function prompt(question) {
231
+ return new Promise((resolve) => {
232
+ const rl = readline.createInterface({
233
+ input: process.stdin,
234
+ output: process.stdout
235
+ });
236
+ rl.question(`${chalk.cyan("?")} ${question}: `, (answer) => {
237
+ rl.close();
238
+ resolve(answer.trim());
239
+ });
240
+ });
241
+ }
242
+ function promptYesNo(question, defaultValue) {
243
+ return new Promise((resolve) => {
244
+ const rl = readline.createInterface({
245
+ input: process.stdin,
246
+ output: process.stdout
247
+ });
248
+ const hint = defaultValue ? "(Y/n)" : "(y/N)";
249
+ rl.question(`${chalk.cyan("?")} ${question} ${hint}: `, (answer) => {
250
+ rl.close();
251
+ if (answer.trim() === "") {
252
+ resolve(defaultValue);
253
+ } else {
254
+ resolve(answer.toLowerCase().startsWith("y"));
255
+ }
256
+ });
257
+ });
258
+ }
259
+
260
+ export {
261
+ promptTierSelection,
262
+ handleTierSetup,
263
+ showTierSwitchMenu,
264
+ updateUserTier
265
+ };
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-5IQKC2TD.js";
5
5
  import {
6
6
  loadConfig
7
- } from "./chunk-IVY5AHPS.js";
7
+ } from "./chunk-Y7DQ5XTU.js";
8
8
 
9
9
  // src/cli/bug.ts
10
10
  import chalk from "chalk";
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-M4LGRTLC.js";
5
5
  import {
6
6
  loadAtom
7
- } from "./chunk-RCW22YNI.js";
7
+ } from "./chunk-5HVYNCLT.js";
8
8
  import {
9
9
  transitionAtom
10
10
  } from "./chunk-5IQKC2TD.js";
@@ -15,7 +15,7 @@ import {
15
15
  import {
16
16
  getAuthToken,
17
17
  loadConfig
18
- } from "./chunk-IVY5AHPS.js";
18
+ } from "./chunk-Y7DQ5XTU.js";
19
19
  import {
20
20
  ArchitectureParser
21
21
  } from "./chunk-5EVHUDQX.js";
@@ -4815,7 +4815,7 @@ function createPrompt() {
4815
4815
  }
4816
4816
  async function execute(atomId, options) {
4817
4817
  if (options.parallel && options.parallel.length > 0) {
4818
- const { parallelExecute } = await import("./parallel-5WJAXTYL.js");
4818
+ const { parallelExecute } = await import("./parallel-IC6FLPSK.js");
4819
4819
  const allAtomIds = [atomId, ...options.parallel];
4820
4820
  await parallelExecute(allAtomIds);
4821
4821
  return;
@@ -5114,7 +5114,7 @@ async function watchCloudExecution(executionId) {
5114
5114
  const pollInterval = 5e3;
5115
5115
  let lastLogCount = 0;
5116
5116
  const poll = async () => {
5117
- const { loadConfig: loadConfig2, getAuthToken: getAuthToken2 } = await import("./config-FTSBI4XE.js");
5117
+ const { loadConfig: loadConfig2, getAuthToken: getAuthToken2 } = await import("./config-SU5Y6MKO.js");
5118
5118
  const { createClient: createClient2 } = await import("@supabase/supabase-js");
5119
5119
  const { SUPABASE_URL: SUPABASE_URL2, SUPABASE_ANON_KEY: SUPABASE_ANON_KEY2 } = await import("./constants-AHP5F7HW.js");
5120
5120
  const config = await loadConfig2();
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  loadAtom
3
- } from "./chunk-RCW22YNI.js";
3
+ } from "./chunk-5HVYNCLT.js";
4
4
 
5
5
  // src/cli/parallel.ts
6
6
  import chalk from "chalk";
@@ -1,3 +1,6 @@
1
+ import {
2
+ login
3
+ } from "./chunk-2BPIPDFV.js";
1
4
  import {
2
5
  keyManager
3
6
  } from "./chunk-SMR7JQK6.js";
@@ -5,7 +8,7 @@ import {
5
8
  getApiUrl,
6
9
  getAuthToken,
7
10
  loadConfig
8
- } from "./chunk-IVY5AHPS.js";
11
+ } from "./chunk-Y7DQ5XTU.js";
9
12
 
10
13
  // src/cli/preferences.ts
11
14
  import chalk from "chalk";
@@ -541,6 +544,23 @@ function prompt(question) {
541
544
  });
542
545
  });
543
546
  }
547
+ function promptYesNo(question, defaultValue) {
548
+ return new Promise((resolve) => {
549
+ const rl = readline.createInterface({
550
+ input: process.stdin,
551
+ output: process.stdout
552
+ });
553
+ const hint = defaultValue ? "(Y/n)" : "(y/N)";
554
+ rl.question(`${chalk.cyan("?")} ${question} ${hint}: `, (answer) => {
555
+ rl.close();
556
+ if (answer.trim() === "") {
557
+ resolve(defaultValue);
558
+ } else {
559
+ resolve(answer.toLowerCase().startsWith("y"));
560
+ }
561
+ });
562
+ });
563
+ }
544
564
  function formatCost(dollars) {
545
565
  if (dollars < 0.01) {
546
566
  return `$${dollars.toFixed(4)}`;
@@ -557,9 +577,7 @@ function formatTokens(tokens) {
557
577
  return tokens.toString();
558
578
  }
559
579
  async function interactiveSettings() {
560
- console.log(chalk.blue("\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
561
- console.log(chalk.bold.white(" Settings & Preferences"));
562
- console.log(chalk.blue("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n"));
580
+ console.log(chalk.bold("\nSettings & Preferences\n"));
563
581
  const spinner = ora("Loading settings...").start();
564
582
  const [profile, usage, providers] = await Promise.all([
565
583
  fetchUserProfile(),
@@ -568,7 +586,12 @@ async function interactiveSettings() {
568
586
  ]);
569
587
  spinner.stop();
570
588
  if (!profile) {
571
- console.log(chalk.yellow("Not logged in. Run: archon login\n"));
589
+ console.log(chalk.yellow("Not logged in.\n"));
590
+ const shouldLogin = await promptYesNo("Would you like to login now?", true);
591
+ if (shouldLogin) {
592
+ await login("github");
593
+ await interactiveSettings();
594
+ }
572
595
  return;
573
596
  }
574
597
  await displayCurrentSettings(profile, usage, providers);
@@ -759,7 +782,7 @@ async function manageApiKeys() {
759
782
  if (removeIndex >= 0 && removeIndex < providers.length) {
760
783
  const providerToRemove = providers[removeIndex];
761
784
  if (providerToRemove) {
762
- const { removeKey } = await import("./keys-IHYIP43K.js");
785
+ const { removeKey } = await import("./keys-76UFD2QR.js");
763
786
  await removeKey(providerToRemove);
764
787
  }
765
788
  }
@@ -767,7 +790,7 @@ async function manageApiKeys() {
767
790
  }
768
791
  const provider = providerMap[choice];
769
792
  if (provider) {
770
- const { addKey } = await import("./keys-IHYIP43K.js");
793
+ const { addKey } = await import("./keys-76UFD2QR.js");
771
794
  await addKey(provider);
772
795
  }
773
796
  }
@@ -3,8 +3,11 @@ import { homedir } from "os";
3
3
  import { join } from "path";
4
4
  import { readFile, writeFile, mkdir, chmod, unlink } from "fs/promises";
5
5
  import { existsSync } from "fs";
6
+ import { createClient } from "@supabase/supabase-js";
6
7
  var CONFIG_DIR = join(homedir(), ".archon");
7
8
  var CONFIG_FILE = join(CONFIG_DIR, "config.json");
9
+ var SUPABASE_URL = "https://yjdkcepktrbabmzhcmrt.supabase.co";
10
+ var SUPABASE_ANON_KEY = "sb_publishable_XSGLVPfLZx-HA2uL6xsGCQ_KjAx2TIa";
8
11
  function getAuthToken(config) {
9
12
  return config.accessToken;
10
13
  }
@@ -45,12 +48,52 @@ async function isAuthenticated() {
45
48
  }
46
49
  if (config.expiresAt) {
47
50
  const expiresAt = new Date(config.expiresAt);
48
- if (expiresAt < /* @__PURE__ */ new Date()) {
49
- return false;
51
+ const now = /* @__PURE__ */ new Date();
52
+ const fiveMinutesFromNow = new Date(now.getTime() + 5 * 60 * 1e3);
53
+ if (expiresAt < fiveMinutesFromNow) {
54
+ if (config.refreshToken) {
55
+ const refreshed = await refreshSession(config);
56
+ return refreshed;
57
+ }
58
+ if (expiresAt < now) {
59
+ return false;
60
+ }
50
61
  }
51
62
  }
52
63
  return true;
53
64
  }
65
+ async function refreshSession(config) {
66
+ if (!config.refreshToken) {
67
+ return false;
68
+ }
69
+ try {
70
+ const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
71
+ auth: { flowType: "pkce" }
72
+ });
73
+ const { data, error } = await supabase.auth.refreshSession({
74
+ refresh_token: config.refreshToken
75
+ });
76
+ if (error || !data.session) {
77
+ return false;
78
+ }
79
+ await saveConfig({
80
+ ...config,
81
+ accessToken: data.session.access_token,
82
+ refreshToken: data.session.refresh_token,
83
+ expiresAt: new Date(data.session.expires_at ?? Date.now() + 36e5).toISOString()
84
+ });
85
+ return true;
86
+ } catch {
87
+ return false;
88
+ }
89
+ }
90
+ async function ensureValidSession() {
91
+ const isAuth = await isAuthenticated();
92
+ if (!isAuth) {
93
+ return null;
94
+ }
95
+ return await loadConfig();
96
+ }
54
97
  async function getCurrentUser() {
55
98
  const config = await loadConfig();
56
99
  if (!config.accessToken || !config.email) {
@@ -70,5 +113,6 @@ export {
70
113
  saveConfig,
71
114
  clearConfig,
72
115
  isAuthenticated,
116
+ ensureValidSession,
73
117
  getCurrentUser
74
118
  };
@@ -1,15 +1,17 @@
1
1
  import {
2
2
  clearConfig,
3
+ ensureValidSession,
3
4
  getApiUrl,
4
5
  getAuthToken,
5
6
  getCurrentUser,
6
7
  isAuthenticated,
7
8
  loadConfig,
8
9
  saveConfig
9
- } from "./chunk-IVY5AHPS.js";
10
+ } from "./chunk-Y7DQ5XTU.js";
10
11
  import "./chunk-QGM4M3NI.js";
11
12
  export {
12
13
  clearConfig,
14
+ ensureValidSession,
13
15
  getApiUrl,
14
16
  getAuthToken,
15
17
  getCurrentUser,
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  execute
3
- } from "./chunk-3NPZQOK2.js";
3
+ } from "./chunk-HGO4UUAC.js";
4
4
  import "./chunk-M4LGRTLC.js";
5
- import "./chunk-RCW22YNI.js";
5
+ import "./chunk-5HVYNCLT.js";
6
6
  import "./chunk-5IQKC2TD.js";
7
- import "./chunk-A7QU6JC6.js";
8
7
  import "./chunk-SMR7JQK6.js";
9
- import "./chunk-IVY5AHPS.js";
8
+ import "./chunk-A7QU6JC6.js";
9
+ import "./chunk-Y7DQ5XTU.js";
10
10
  import "./chunk-5EVHUDQX.js";
11
11
  import "./chunk-QGM4M3NI.js";
12
12
  export {
package/dist/index.js CHANGED
@@ -1,4 +1,17 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ listModels,
4
+ resetPreferences,
5
+ setExecutionPreference,
6
+ setPreference,
7
+ showExecutionPreferences,
8
+ showPreferences
9
+ } from "./chunk-XP7PNLXG.js";
10
+ import {
11
+ parallelClean,
12
+ parallelMerge,
13
+ parallelStatus
14
+ } from "./chunk-OI4K3RYO.js";
2
15
  import {
3
16
  DependencyParser,
4
17
  EnvironmentConfigLoader,
@@ -7,19 +20,19 @@ import {
7
20
  cloudLogs,
8
21
  cloudStatus,
9
22
  execute
10
- } from "./chunk-3NPZQOK2.js";
23
+ } from "./chunk-HGO4UUAC.js";
11
24
  import {
12
25
  list
13
- } from "./chunk-TEY4GCMH.js";
26
+ } from "./chunk-7FJ4ATJE.js";
14
27
  import {
15
28
  bugReport
16
- } from "./chunk-KF6MFAB4.js";
29
+ } from "./chunk-GLBVZOBA.js";
17
30
  import {
18
31
  addKey,
19
32
  listKeys,
20
33
  removeKey,
21
34
  setPrimaryKey
22
- } from "./chunk-SSSEOM25.js";
35
+ } from "./chunk-BBAUT4M5.js";
23
36
  import {
24
37
  reviewAnalyze,
25
38
  reviewExport,
@@ -33,19 +46,12 @@ import {
33
46
  reviewUpdate
34
47
  } from "./chunk-QSYKKPFF.js";
35
48
  import "./chunk-VKM3HAHW.js";
36
- import {
37
- listModels,
38
- resetPreferences,
39
- setExecutionPreference,
40
- setPreference,
41
- showExecutionPreferences,
42
- showPreferences
43
- } from "./chunk-E2M23XSZ.js";
44
49
  import {
45
50
  login,
46
51
  logout,
47
52
  status
48
- } from "./chunk-UI4UQ24R.js";
53
+ } from "./chunk-2BPIPDFV.js";
54
+ import "./chunk-C5TDNTNC.js";
49
55
  import {
50
56
  API_URL,
51
57
  SUPABASE_ANON_KEY,
@@ -55,25 +61,20 @@ import {
55
61
  init,
56
62
  isInitialized
57
63
  } from "./chunk-P666JE3G.js";
58
- import {
59
- parallelClean,
60
- parallelMerge,
61
- parallelStatus
62
- } from "./chunk-TSSFMB6E.js";
63
64
  import {
64
65
  listLocalAtoms,
65
66
  loadAtom,
66
67
  plan
67
- } from "./chunk-RCW22YNI.js";
68
+ } from "./chunk-5HVYNCLT.js";
68
69
  import {
69
70
  ArchitectAgent
70
71
  } from "./chunk-5IQKC2TD.js";
71
- import "./chunk-A7QU6JC6.js";
72
72
  import "./chunk-SMR7JQK6.js";
73
+ import "./chunk-A7QU6JC6.js";
73
74
  import {
74
75
  getAuthToken,
75
76
  loadConfig
76
- } from "./chunk-IVY5AHPS.js";
77
+ } from "./chunk-Y7DQ5XTU.js";
77
78
  import {
78
79
  ArchitectureParser
79
80
  } from "./chunk-5EVHUDQX.js";
@@ -873,9 +874,18 @@ async function runAutoCleanupCheck(cwd) {
873
874
  async function start(options = {}) {
874
875
  const cwd = process.cwd();
875
876
  if (!options.skipGovernanceBanner) {
876
- console.log(chalk4.bold.white("\nArchonDev - AI-Powered Development Governance"));
877
+ console.log(chalk4.bold("\nArchonDev - AI-Powered Development Governance"));
877
878
  console.log(chalk4.blue("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n"));
878
879
  }
880
+ const token = await getAuthToken();
881
+ if (!token) {
882
+ console.log(chalk4.yellow("[!] Not logged in"));
883
+ const shouldLogin = await promptYesNo("Would you like to login now?", true);
884
+ if (shouldLogin) {
885
+ await login();
886
+ console.log();
887
+ }
888
+ }
879
889
  const contextManager = new ContextManager();
880
890
  const pendingAtomsData = await contextManager.getPendingAtomsData(cwd);
881
891
  if (pendingAtomsData && pendingAtomsData.atoms.length > 0) {
@@ -902,7 +912,7 @@ async function start(options = {}) {
902
912
  const projectState = detectProjectState(cwd);
903
913
  if (!options.skipGovernanceBanner) {
904
914
  const governanceStatus = await gatherGovernanceStatus(cwd);
905
- displayGovernanceBanner(governanceStatus);
915
+ await displayGovernanceBanner(governanceStatus);
906
916
  }
907
917
  if (await shouldRunAutoCleanup(cwd)) {
908
918
  await runAutoCleanupCheck(cwd);
@@ -1031,15 +1041,21 @@ async function gatherGovernanceStatus(cwd) {
1031
1041
  }
1032
1042
  return status2;
1033
1043
  }
1034
- function displayGovernanceBanner(status2) {
1035
- console.log(chalk4.bold.white("Governance Status"));
1044
+ async function displayGovernanceBanner(status2) {
1045
+ console.log(chalk4.bold("Governance Status"));
1036
1046
  console.log(chalk4.blue("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
1037
1047
  if (status2.hasArchitecture) {
1038
1048
  console.log(chalk4.green(" \u2713") + ` ARCHITECTURE.md loaded (${status2.posture} posture)`);
1039
1049
  console.log(chalk4.green(" \u2713") + ` ${status2.invariantsCount} invariants enforced`);
1040
1050
  console.log(chalk4.green(" \u2713") + ` ${status2.protectedPathsCount} protected paths defined`);
1041
1051
  } else {
1042
- console.log(chalk4.yellow(" [!]") + " ARCHITECTURE.md not found - run " + chalk4.cyan("archon init"));
1052
+ console.log(chalk4.yellow(" [!]") + " ARCHITECTURE.md not found.");
1053
+ const shouldInit = await promptYesNo("Would you like to initialize now?", true);
1054
+ if (shouldInit) {
1055
+ const { init: init2 } = await import("./init-6EXMDCWC.js");
1056
+ await init2({ analyze: true, git: true });
1057
+ console.log();
1058
+ }
1043
1059
  }
1044
1060
  console.log(chalk4.green(" \u2713") + ` ${status2.dependencyRulesCount} dependency rules active`);
1045
1061
  if (status2.lastSessionDate) {
@@ -1153,13 +1169,13 @@ ${noNoPatterns ? `- **Forbidden patterns:** ${noNoPatterns}` : "- No forbidden p
1153
1169
  if (continueChoice) {
1154
1170
  const description = await prompt("Describe what you want to build first");
1155
1171
  if (description.trim()) {
1156
- const { plan: plan2 } = await import("./plan-W2UXAR6E.js");
1172
+ const { plan: plan2 } = await import("./plan-TVTKS655.js");
1157
1173
  await plan2(description, {});
1158
1174
  }
1159
1175
  }
1160
1176
  }
1161
1177
  async function quickStart(cwd) {
1162
- console.log(chalk4.blue("\n\u2501\u2501\u2501 Quick Start \u2501\u2501\u2501\n"));
1178
+ console.log(chalk4.blue("\n-- Quick Start --\n"));
1163
1179
  const { init: init2 } = await import("./init-6EXMDCWC.js");
1164
1180
  await init2({ analyze: false, git: true });
1165
1181
  const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
@@ -1186,7 +1202,7 @@ This file tracks learnings and decisions across sessions.
1186
1202
  await showMainMenu();
1187
1203
  }
1188
1204
  async function handleAdaptExisting(cwd, state) {
1189
- console.log(chalk4.yellow("\u{1F4C1}") + chalk4.bold(" Existing project detected!\n"));
1205
+ console.log(chalk4.bold("Existing project detected!\n"));
1190
1206
  console.log(chalk4.dim("I can analyze your codebase and adapt the governance files to match your structure."));
1191
1207
  console.log(chalk4.dim("This helps me understand your architecture without changing any code.\n"));
1192
1208
  console.log(chalk4.bold("What would you like to do?\n"));
@@ -1218,7 +1234,7 @@ async function handleAdaptExisting(cwd, state) {
1218
1234
  }
1219
1235
  }
1220
1236
  async function analyzeAndAdapt(cwd) {
1221
- console.log(chalk4.blue("\n\u2501\u2501\u2501 Analyzing Project \u2501\u2501\u2501\n"));
1237
+ console.log(chalk4.blue("\n-- Analyzing Project --\n"));
1222
1238
  const { init: init2 } = await import("./init-6EXMDCWC.js");
1223
1239
  await init2({ analyze: true, git: true });
1224
1240
  const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
@@ -1244,7 +1260,7 @@ async function analyzeAndAdapt(cwd) {
1244
1260
  await showMainMenu();
1245
1261
  }
1246
1262
  async function codeReviewFirst(cwd) {
1247
- console.log(chalk4.blue("\n\u2501\u2501\u2501 Code Review Mode \u2501\u2501\u2501\n"));
1263
+ console.log(chalk4.blue("\n-- Code Review Mode --\n"));
1248
1264
  console.log(chalk4.dim("I'll analyze your code for issues without making any changes.\n"));
1249
1265
  const { reviewInit: reviewInit2, reviewAnalyze: reviewAnalyze2, reviewRun: reviewRun2 } = await import("./review-QV4TQM2Z.js");
1250
1266
  const reviewDbPath = join4(cwd, "docs", "code-review", "review-tasks.db");
@@ -1259,7 +1275,7 @@ async function codeReviewFirst(cwd) {
1259
1275
  console.log(chalk4.dim("\nAfter reviewing, you can run ") + chalk4.cyan("archon") + chalk4.dim(" again to set up governance.\n"));
1260
1276
  }
1261
1277
  async function manualSetup(cwd) {
1262
- console.log(chalk4.blue("\n\u2501\u2501\u2501 Manual Setup \u2501\u2501\u2501\n"));
1278
+ console.log(chalk4.blue("\n-- Manual Setup --\n"));
1263
1279
  console.log(chalk4.dim("Creating template files. You can customize them manually.\n"));
1264
1280
  const { init: init2 } = await import("./init-6EXMDCWC.js");
1265
1281
  await init2({ analyze: false, git: true });
@@ -1374,20 +1390,20 @@ async function showReviewProgress(cwd) {
1374
1390
  }
1375
1391
  }
1376
1392
  async function planTask() {
1377
- const { plan: plan2 } = await import("./plan-W2UXAR6E.js");
1393
+ const { plan: plan2 } = await import("./plan-TVTKS655.js");
1378
1394
  const description = await prompt("Describe what you want to build");
1379
1395
  if (description.trim()) {
1380
1396
  await plan2(description, {});
1381
1397
  }
1382
1398
  }
1383
1399
  async function listAtoms() {
1384
- const { list: list2 } = await import("./list-LEFAISNL.js");
1400
+ const { list: list2 } = await import("./list-XZ42CNFC.js");
1385
1401
  await list2({});
1386
1402
  }
1387
1403
  async function executeNext() {
1388
- const { listLocalAtoms: listLocalAtoms2 } = await import("./plan-W2UXAR6E.js");
1404
+ const { listLocalAtoms: listLocalAtoms2 } = await import("./plan-TVTKS655.js");
1389
1405
  const { analyzeProject, getComplexityDescription, getModeDescription } = await import("./orchestration-X6LHSHBJ.js");
1390
- const { loadExecutionPreferences } = await import("./preferences-ZJ4TX2RC.js");
1406
+ const { loadExecutionPreferences } = await import("./preferences-VY6WPI6V.js");
1391
1407
  const cwd = process.cwd();
1392
1408
  const atoms = await listLocalAtoms2();
1393
1409
  const pendingAtoms = atoms.filter((a) => a.status === "READY" || a.status === "IN_PROGRESS");
@@ -1420,25 +1436,25 @@ async function executeNext() {
1420
1436
  const atomId = await prompt("Enter atom ID to execute (or press Enter for first pending)");
1421
1437
  const targetId = atomId.trim() || pendingAtoms[0]?.id;
1422
1438
  if (targetId) {
1423
- const { execute: execute2 } = await import("./execute-5ZSLSWPZ.js");
1439
+ const { execute: execute2 } = await import("./execute-6D6USH33.js");
1424
1440
  await execute2(targetId, {});
1425
1441
  } else {
1426
1442
  console.log(chalk4.yellow("No atom to execute."));
1427
1443
  }
1428
1444
  }
1429
1445
  async function reportBug() {
1430
- const { bugReport: bugReport2 } = await import("./bug-K4V357B2.js");
1446
+ const { bugReport: bugReport2 } = await import("./bug-IT4C6HIG.js");
1431
1447
  const title = await prompt("Bug title");
1432
1448
  if (title.trim()) {
1433
1449
  await bugReport2(title, {});
1434
1450
  }
1435
1451
  }
1436
1452
  async function viewStatus() {
1437
- const { status: status2 } = await import("./auth-COINREKK.js");
1453
+ const { status: status2 } = await import("./auth-R6G5RDJE.js");
1438
1454
  await status2();
1439
1455
  }
1440
1456
  async function settingsMenu() {
1441
- const { interactiveSettings } = await import("./preferences-ZJ4TX2RC.js");
1457
+ const { interactiveSettings } = await import("./preferences-VY6WPI6V.js");
1442
1458
  await interactiveSettings();
1443
1459
  await showMainMenu();
1444
1460
  }
@@ -1597,7 +1613,7 @@ async function addCredits(options = {}) {
1597
1613
  spinner.fail("Not logged in. Run: archon login");
1598
1614
  return;
1599
1615
  }
1600
- const amountDollars = options.amount ? parseFloat(options.amount) : 10;
1616
+ const amountDollars = options.amount ? parseFloat(options.amount) : 5;
1601
1617
  if (isNaN(amountDollars) || amountDollars < 5) {
1602
1618
  spinner.fail("Minimum purchase is $5.00");
1603
1619
  return;
@@ -4758,6 +4774,10 @@ program.command("logout").description("Clear stored authentication").action(asyn
4758
4774
  program.command("status").description("Show current user and project status").action(async () => {
4759
4775
  await status();
4760
4776
  });
4777
+ program.command("pricing").description("View and switch pricing tiers (Free, BYOK, Credits)").action(async () => {
4778
+ const { showTierSwitchMenu } = await import("./tier-selection-JYMYBIRV.js");
4779
+ await showTierSwitchMenu();
4780
+ });
4761
4781
  program.command("init").description("Initialize ArchonDev in current project").option("--analyze", "Run enhanced analysis of codebase").option("--no-git", "Skip git initialization").action(async (options) => {
4762
4782
  await init(options);
4763
4783
  });
@@ -4801,7 +4821,7 @@ var creditsCommand = program.command("credits").description("Manage credit balan
4801
4821
  creditsCommand.command("show").description("Show current credit balance").action(async () => {
4802
4822
  await showCredits();
4803
4823
  });
4804
- creditsCommand.command("add").description("Add credits via Stripe checkout").option("-a, --amount <dollars>", "Amount in dollars (min $5)", "10").action(async (options) => {
4824
+ creditsCommand.command("add").description("Add credits via Stripe checkout").option("-a, --amount <dollars>", "Amount in dollars (min $5)", "5").action(async (options) => {
4805
4825
  await addCredits(options);
4806
4826
  });
4807
4827
  creditsCommand.command("history").description("Show recent token usage").option("-l, --limit <count>", "Number of records to show", "20").action(async (options) => {
@@ -3,9 +3,9 @@ import {
3
3
  listKeys,
4
4
  removeKey,
5
5
  setPrimaryKey
6
- } from "./chunk-SSSEOM25.js";
6
+ } from "./chunk-BBAUT4M5.js";
7
7
  import "./chunk-SMR7JQK6.js";
8
- import "./chunk-IVY5AHPS.js";
8
+ import "./chunk-Y7DQ5XTU.js";
9
9
  import "./chunk-QGM4M3NI.js";
10
10
  export {
11
11
  addKey,
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  list
3
- } from "./chunk-TEY4GCMH.js";
4
- import "./chunk-RCW22YNI.js";
3
+ } from "./chunk-7FJ4ATJE.js";
4
+ import "./chunk-5HVYNCLT.js";
5
5
  import "./chunk-5IQKC2TD.js";
6
- import "./chunk-A7QU6JC6.js";
7
6
  import "./chunk-SMR7JQK6.js";
8
- import "./chunk-IVY5AHPS.js";
7
+ import "./chunk-A7QU6JC6.js";
8
+ import "./chunk-Y7DQ5XTU.js";
9
9
  import "./chunk-5EVHUDQX.js";
10
10
  import "./chunk-QGM4M3NI.js";
11
11
  export {
@@ -3,12 +3,12 @@ import {
3
3
  parallelExecute,
4
4
  parallelMerge,
5
5
  parallelStatus
6
- } from "./chunk-TSSFMB6E.js";
7
- import "./chunk-RCW22YNI.js";
6
+ } from "./chunk-OI4K3RYO.js";
7
+ import "./chunk-5HVYNCLT.js";
8
8
  import "./chunk-5IQKC2TD.js";
9
- import "./chunk-A7QU6JC6.js";
10
9
  import "./chunk-SMR7JQK6.js";
11
- import "./chunk-IVY5AHPS.js";
10
+ import "./chunk-A7QU6JC6.js";
11
+ import "./chunk-Y7DQ5XTU.js";
12
12
  import "./chunk-5EVHUDQX.js";
13
13
  import "./chunk-QGM4M3NI.js";
14
14
  export {
@@ -2,11 +2,11 @@ import {
2
2
  listLocalAtoms,
3
3
  loadAtom,
4
4
  plan
5
- } from "./chunk-RCW22YNI.js";
5
+ } from "./chunk-5HVYNCLT.js";
6
6
  import "./chunk-5IQKC2TD.js";
7
- import "./chunk-A7QU6JC6.js";
8
7
  import "./chunk-SMR7JQK6.js";
9
- import "./chunk-IVY5AHPS.js";
8
+ import "./chunk-A7QU6JC6.js";
9
+ import "./chunk-Y7DQ5XTU.js";
10
10
  import "./chunk-5EVHUDQX.js";
11
11
  import "./chunk-QGM4M3NI.js";
12
12
  export {
@@ -7,9 +7,12 @@ import {
7
7
  setPreference,
8
8
  showExecutionPreferences,
9
9
  showPreferences
10
- } from "./chunk-E2M23XSZ.js";
10
+ } from "./chunk-XP7PNLXG.js";
11
+ import "./chunk-2BPIPDFV.js";
12
+ import "./chunk-C5TDNTNC.js";
13
+ import "./chunk-M4LGRTLC.js";
11
14
  import "./chunk-SMR7JQK6.js";
12
- import "./chunk-IVY5AHPS.js";
15
+ import "./chunk-Y7DQ5XTU.js";
13
16
  import "./chunk-QGM4M3NI.js";
14
17
  export {
15
18
  interactiveSettings,
@@ -0,0 +1,15 @@
1
+ import {
2
+ handleTierSetup,
3
+ promptTierSelection,
4
+ showTierSwitchMenu,
5
+ updateUserTier
6
+ } from "./chunk-C5TDNTNC.js";
7
+ import "./chunk-M4LGRTLC.js";
8
+ import "./chunk-Y7DQ5XTU.js";
9
+ import "./chunk-QGM4M3NI.js";
10
+ export {
11
+ handleTierSetup,
12
+ promptTierSelection,
13
+ showTierSwitchMenu,
14
+ updateUserTier
15
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "archondev",
3
- "version": "2.1.4",
3
+ "version": "2.2.0",
4
4
  "description": "Local-first AI-powered development governance system",
5
5
  "main": "dist/index.js",
6
6
  "bin": {