archondev 2.18.7 → 2.19.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/dist/index.js CHANGED
@@ -4,10 +4,10 @@ import {
4
4
  } from "./chunk-JF7JCK6H.js";
5
5
  import {
6
6
  createGeoCommand
7
- } from "./chunk-OAHFRSDS.js";
7
+ } from "./chunk-O3B6BE5D.js";
8
8
  import {
9
9
  bugReport
10
- } from "./chunk-2BCITFWP.js";
10
+ } from "./chunk-DCIIYVJW.js";
11
11
  import {
12
12
  reviewAnalyze,
13
13
  reviewExport,
@@ -19,8 +19,8 @@ import {
19
19
  reviewShow,
20
20
  reviewStatus,
21
21
  reviewUpdate
22
- } from "./chunk-BFPWDOMA.js";
23
- import "./chunk-HGLPIM7J.js";
22
+ } from "./chunk-M6GNIN64.js";
23
+ import "./chunk-KG35EHZY.js";
24
24
  import {
25
25
  resetPreferences,
26
26
  setExecutionPreference,
@@ -46,13 +46,13 @@ import {
46
46
  parallelRunWaves,
47
47
  parallelSchedule,
48
48
  parallelStatus
49
- } from "./chunk-ICSHS6BW.js";
49
+ } from "./chunk-QTBRLNZQ.js";
50
50
  import {
51
51
  DependencyParser,
52
52
  EnvironmentConfigLoader,
53
53
  EnvironmentValidator,
54
54
  execute
55
- } from "./chunk-MRRA3QDP.js";
55
+ } from "./chunk-OREGEFTF.js";
56
56
  import {
57
57
  cloudCancel,
58
58
  cloudLogs,
@@ -60,15 +60,19 @@ import {
60
60
  } from "./chunk-EBHHIUCB.js";
61
61
  import {
62
62
  list
63
- } from "./chunk-YFCC6QEY.js";
63
+ } from "./chunk-YA562WHL.js";
64
64
  import {
65
65
  listLocalAtoms,
66
66
  loadAtom,
67
67
  plan
68
- } from "./chunk-ESSNYHC7.js";
69
- import "./chunk-5CFGPXQ3.js";
70
- import "./chunk-5BYCJAFM.js";
71
- import "./chunk-HJARQDQR.js";
68
+ } from "./chunk-ACFMKTDL.js";
69
+ import "./chunk-PCTP3LKJ.js";
70
+ import "./chunk-PJRQI5UN.js";
71
+ import {
72
+ err,
73
+ ok,
74
+ sleep
75
+ } from "./chunk-EIEU3IIY.js";
72
76
  import {
73
77
  createAuthedSupabaseClient
74
78
  } from "./chunk-Q3GIFHIQ.js";
@@ -107,8 +111,8 @@ import {
107
111
  import "./chunk-4VNS5WPM.js";
108
112
 
109
113
  // src/cli/index.ts
110
- import { Command as Command2 } from "commander";
111
- import chalk17 from "chalk";
114
+ import { Command as Command3 } from "commander";
115
+ import chalk18 from "chalk";
112
116
  import "dotenv/config";
113
117
 
114
118
  // src/cli/promote.ts
@@ -427,8 +431,8 @@ var ContextManager = class _ContextManager {
427
431
  async clearPendingAtoms(cwd) {
428
432
  const filePath = join2(cwd, _ContextManager.PENDING_ATOMS_FILE);
429
433
  if (existsSync2(filePath)) {
430
- const { unlink: unlink2 } = await import("fs/promises");
431
- await unlink2(filePath);
434
+ const { unlink: unlink4 } = await import("fs/promises");
435
+ await unlink4(filePath);
432
436
  }
433
437
  }
434
438
  };
@@ -1199,8 +1203,12 @@ function extractTechStackHints(message) {
1199
1203
  if (/typescript|\.ts\b/i.test(message)) hints.language = "typescript";
1200
1204
  else if (/javascript|\.js\b/i.test(message)) hints.language = "javascript";
1201
1205
  else if (/python|\.py\b/i.test(message)) hints.language = "python";
1202
- else if (/go(lang)?|\.go\b/i.test(message)) hints.language = "go";
1203
- else if (/rust|\.rs\b/i.test(message)) hints.language = "rust";
1206
+ else if (/\bgolang\b|\.go\b/i.test(message)) hints.language = "go";
1207
+ else if (/\bgo\b/i.test(message)) {
1208
+ if (/\bgo (lang|language|backend|server|api|service|cli)\b/i.test(message) || /\bin go\b/i.test(message)) {
1209
+ hints.language = "go";
1210
+ }
1211
+ } else if (/rust|\.rs\b/i.test(message)) hints.language = "rust";
1204
1212
  if (/next\.?js|next/i.test(message)) hints.framework = "nextjs";
1205
1213
  else if (/react/i.test(message)) hints.framework = "react";
1206
1214
  else if (/vue/i.test(message)) hints.framework = "vue";
@@ -2734,7 +2742,7 @@ async function start(options = {}) {
2734
2742
  }
2735
2743
  }
2736
2744
  if (!config.tier || config.tier === "FREE") {
2737
- const isFirstRun = !existsSync6(join6(cwd, ".archon")) && !existsSync6(join6(cwd, "ARCHITECTURE.md"));
2745
+ const isFirstRun = !existsSync6(join6(cwd, ".archon")) && resolveArchitecturePath(cwd).path === null;
2738
2746
  if (isFirstRun && !config.tierConfirmed) {
2739
2747
  console.log(chalk6.bold("How would you like to use ArchonDev?\n"));
2740
2748
  const selection = await promptTierSelection();
@@ -2771,7 +2779,22 @@ async function start(options = {}) {
2771
2779
  }
2772
2780
  if (currentTier === "CREDITS" && config.accessToken) {
2773
2781
  try {
2774
- const usageStats = config.userId ? await fetchCreditsUsageStats(config.accessToken, config.userId) : null;
2782
+ const resolvedAuthId = await resolveAuthIdFromToken(config.accessToken, config.userId);
2783
+ if (resolvedAuthId && !config.userId) {
2784
+ await saveConfig({ ...config, userId: resolvedAuthId });
2785
+ }
2786
+ let usageStats = resolvedAuthId ? await fetchCreditsUsageStats(config.accessToken, resolvedAuthId) : null;
2787
+ const usageStatsUnavailable = !usageStats;
2788
+ if (!usageStats) {
2789
+ usageStats = {
2790
+ balance: 0,
2791
+ usedThisPeriod: 0,
2792
+ byModel: [],
2793
+ periodStart: void 0,
2794
+ periodSource: void 0,
2795
+ lastCreditPurchaseAt: null
2796
+ };
2797
+ }
2775
2798
  if (usageStats) {
2776
2799
  console.log();
2777
2800
  console.log(chalk6.bold("\u{1F4B0} Credits Balance"));
@@ -2789,15 +2812,20 @@ async function start(options = {}) {
2789
2812
  } else {
2790
2813
  console.log(chalk6.dim(" No usage recorded since last top-up."));
2791
2814
  }
2815
+ console.log();
2816
+ console.log(chalk6.dim(" Model Usage:"));
2792
2817
  if (usageStats.byModel && usageStats.byModel.length > 0) {
2793
- console.log();
2794
- console.log(chalk6.dim(" Model Usage:"));
2795
2818
  for (const model of usageStats.byModel) {
2796
2819
  const modelName = model.model.length > 32 ? model.model.slice(0, 29) + "..." : model.model;
2797
2820
  console.log(chalk6.dim(` ${modelName.padEnd(34)} $${model.cost.toFixed(4)}`));
2798
2821
  }
2822
+ } else {
2823
+ console.log(chalk6.dim(` ${"No usage yet".padEnd(34)} $0.0000`));
2799
2824
  }
2800
2825
  console.log(chalk6.dim("\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"));
2826
+ if (usageStatsUnavailable) {
2827
+ console.log(chalk6.dim("Usage details may be delayed. Run `archon credits` to refresh."));
2828
+ }
2801
2829
  if (usageStats.balance < 5) {
2802
2830
  console.log(chalk6.yellow(`\u26A0\uFE0F Low balance! Add credits: `) + chalk6.bold(`archon credits add`));
2803
2831
  } else {
@@ -2819,7 +2847,7 @@ async function start(options = {}) {
2819
2847
  console.log(` ${chalk6.cyan("2")}) Switch to Managed Plan (no keys needed)`);
2820
2848
  console.log(` ${chalk6.cyan("3")}) Continue on Free tier`);
2821
2849
  console.log();
2822
- const choice = await promptWithCommands("What would you like to do?");
2850
+ const choice = await promptWithCommands("What would you like to do?", { allowMultiline: true });
2823
2851
  switch (choice) {
2824
2852
  case "1":
2825
2853
  const { handleTierSetup: handleTierSetup2 } = await import("./tier-selection-426HA765.js");
@@ -2915,6 +2943,20 @@ function formatTierName(tier) {
2915
2943
  return tier;
2916
2944
  }
2917
2945
  }
2946
+ async function resolveAuthIdFromToken(accessToken, existingAuthId) {
2947
+ if (existingAuthId) return existingAuthId;
2948
+ try {
2949
+ const { SUPABASE_URL: SUPABASE_URL2, SUPABASE_ANON_KEY: SUPABASE_ANON_KEY2 } = await import("./constants-XDIWFFPN.js");
2950
+ const { createClient: createClient2 } = await import("@supabase/supabase-js");
2951
+ const client = createClient2(SUPABASE_URL2, SUPABASE_ANON_KEY2, {
2952
+ global: { headers: { Authorization: `Bearer ${accessToken}` } }
2953
+ });
2954
+ const { data: { user } } = await client.auth.getUser();
2955
+ return user?.id ?? null;
2956
+ } catch {
2957
+ return null;
2958
+ }
2959
+ }
2918
2960
  async function fetchCreditsUsageStats(accessToken, authId) {
2919
2961
  try {
2920
2962
  const { API_URL: API_URL3 } = await import("./constants-XDIWFFPN.js");
@@ -2943,16 +2985,19 @@ async function fetchCreditsUsageStatsFromSupabase(accessToken, authId) {
2943
2985
  const { SUPABASE_URL: SUPABASE_URL2, SUPABASE_ANON_KEY: SUPABASE_ANON_KEY2 } = await import("./constants-XDIWFFPN.js");
2944
2986
  const { createAuthedSupabaseClient: createAuthedSupabaseClient2 } = await import("./client-PHW2C2HB.js");
2945
2987
  const supabase = createAuthedSupabaseClient2(SUPABASE_URL2, SUPABASE_ANON_KEY2, accessToken);
2946
- const { data: profile, error: profileError } = await supabase.from("user_profiles").select("id, credit_balance_cents").eq("auth_id", authId).single();
2988
+ const { data: rawProfile, error: profileError } = await supabase.from("user_profiles").select("id, credit_balance_cents").eq("auth_id", authId).single();
2989
+ const profile = rawProfile;
2947
2990
  if (profileError || !profile?.id) {
2948
2991
  return null;
2949
2992
  }
2950
- const { data: lastPurchase } = await supabase.from("credit_purchases").select("created_at").eq("user_id", profile.id).eq("status", "completed").order("created_at", { ascending: false }).limit(1).maybeSingle();
2993
+ const { data: rawLastPurchase } = await supabase.from("credit_purchases").select("created_at").eq("user_id", profile.id).eq("status", "completed").order("created_at", { ascending: false }).limit(1).maybeSingle();
2994
+ const lastPurchase = rawLastPurchase;
2951
2995
  const now = /* @__PURE__ */ new Date();
2952
2996
  const defaultStart = new Date(now.getFullYear(), now.getMonth(), 1).toISOString();
2953
2997
  const periodStart = lastPurchase?.created_at ?? defaultStart;
2954
2998
  const periodSource = lastPurchase?.created_at ? "credit_purchase" : "month";
2955
- const { data: usageRows } = await supabase.from("token_usage").select("model, marked_up_cost, total_cents, created_at").eq("user_id", profile.id).gte("created_at", periodStart);
2999
+ const { data: rawUsageRows } = await supabase.from("token_usage").select("model, marked_up_cost, total_cents, created_at").eq("user_id", profile.id).gte("created_at", periodStart);
3000
+ const usageRows = rawUsageRows;
2956
3001
  const byModelMap = /* @__PURE__ */ new Map();
2957
3002
  let usedThisPeriod = 0;
2958
3003
  for (const row of usageRows ?? []) {
@@ -2989,6 +3034,18 @@ function displayGovernanceStatus(status2) {
2989
3034
  }
2990
3035
  console.log();
2991
3036
  }
3037
+ var ACTIVE_ARCH_PATH = join6(".archon", "active", "architecture.md");
3038
+ function resolveArchitecturePath(cwd) {
3039
+ const agdPath = join6(cwd, ACTIVE_ARCH_PATH);
3040
+ if (existsSync6(agdPath)) {
3041
+ return { path: agdPath, source: "agd" };
3042
+ }
3043
+ const legacyPath = join6(cwd, "ARCHITECTURE.md");
3044
+ if (existsSync6(legacyPath)) {
3045
+ return { path: legacyPath, source: "legacy" };
3046
+ }
3047
+ return { path: null, source: null };
3048
+ }
2992
3049
  function detectProjectState(cwd) {
2993
3050
  const sourceDirs = ["src", "lib", "app", "packages", "components", "pages", "api"];
2994
3051
  const sourceExtensions = [".ts", ".tsx", ".js", ".jsx", ".py", ".go", ".rs", ".java", ".rb", ".php"];
@@ -3012,7 +3069,7 @@ function detectProjectState(cwd) {
3012
3069
  if (!hasSourceFiles) {
3013
3070
  hasSourceFiles = projectMarkers.some((marker) => existsSync6(join6(cwd, marker)));
3014
3071
  }
3015
- const hasArchitecture = existsSync6(join6(cwd, "ARCHITECTURE.md"));
3072
+ const hasArchitecture = resolveArchitecturePath(cwd).path !== null;
3016
3073
  const hasProgress = existsSync6(join6(cwd, "progress.txt"));
3017
3074
  const hasReviewDb = existsSync6(join6(cwd, "docs", "code-review", "review-tasks.db"));
3018
3075
  let hasProgressEntries = false;
@@ -3061,9 +3118,9 @@ async function gatherGovernanceStatus(cwd) {
3061
3118
  dependencyRulesCount: 0,
3062
3119
  pendingAtomsCount: 0
3063
3120
  };
3064
- const archPath = join6(cwd, "ARCHITECTURE.md");
3065
- if (existsSync6(archPath)) {
3066
- const parser = new ArchitectureParser(archPath);
3121
+ const archInfo = resolveArchitecturePath(cwd);
3122
+ if (archInfo.path) {
3123
+ const parser = new ArchitectureParser(archInfo.path);
3067
3124
  const result = await parser.parse();
3068
3125
  if (result.success && result.schema) {
3069
3126
  status2.hasArchitecture = true;
@@ -3108,7 +3165,7 @@ async function handleNewProject(cwd, _state) {
3108
3165
  console.log(chalk6.bold("\u{1F389} Starting a new project? Great!\n"));
3109
3166
  console.log(chalk6.dim("Answer as much or as little as you want \u2014 you can always refine later."));
3110
3167
  console.log(chalk6.dim('Type "just start" or "skip" to use defaults.\n'));
3111
- const initialResponse = await promptWithCommands("What do you want to do?");
3168
+ const initialResponse = await promptWithCommands("What do you want to do?", { allowMultiline: true });
3112
3169
  if (!initialResponse.trim()) {
3113
3170
  console.log(chalk6.yellow("\nNo response provided. Showing options...\n"));
3114
3171
  await showNewProjectMenu(cwd);
@@ -3127,7 +3184,7 @@ async function handleNewProject(cwd, _state) {
3127
3184
  }
3128
3185
  if (intent.mode === "ad_hoc" && intent.confidence >= 0.7) {
3129
3186
  console.log(chalk6.dim("\n> Got it! Creating a task for this...\n"));
3130
- const { plan: plan2 } = await import("./plan-4RIHWWZG.js");
3187
+ const { plan: plan2 } = await import("./plan-HCYXLSSD.js");
3131
3188
  await plan2(initialResponse, {});
3132
3189
  return;
3133
3190
  }
@@ -3151,7 +3208,7 @@ async function handleNewProject(cwd, _state) {
3151
3208
  break;
3152
3209
  case "2":
3153
3210
  console.log(chalk6.dim("\n> Creating a task for this...\n"));
3154
- const { plan: plan2 } = await import("./plan-4RIHWWZG.js");
3211
+ const { plan: plan2 } = await import("./plan-HCYXLSSD.js");
3155
3212
  await plan2(initialResponse, {});
3156
3213
  break;
3157
3214
  case "3":
@@ -3181,7 +3238,7 @@ async function showNewProjectMenu(cwd) {
3181
3238
  case "3": {
3182
3239
  const description = await prompt("Describe what you want to do");
3183
3240
  if (description.trim()) {
3184
- const { plan: plan2 } = await import("./plan-4RIHWWZG.js");
3241
+ const { plan: plan2 } = await import("./plan-HCYXLSSD.js");
3185
3242
  await plan2(description, {});
3186
3243
  }
3187
3244
  break;
@@ -3247,7 +3304,7 @@ async function runExploreFlow(cwd) {
3247
3304
  case "1": {
3248
3305
  const description = await prompt("Describe what you want to do");
3249
3306
  if (description.trim()) {
3250
- const { plan: plan2 } = await import("./plan-4RIHWWZG.js");
3307
+ const { plan: plan2 } = await import("./plan-HCYXLSSD.js");
3251
3308
  await plan2(description, {});
3252
3309
  }
3253
3310
  break;
@@ -3340,11 +3397,14 @@ async function gatherProjectInfo(cwd) {
3340
3397
  }
3341
3398
  } catch {
3342
3399
  }
3343
- info.hasArchitecture = existsSync6(join6(cwd, "ARCHITECTURE.md"));
3400
+ info.hasArchitecture = resolveArchitecturePath(cwd).path !== null;
3344
3401
  info.hasProgress = existsSync6(join6(cwd, "progress.txt"));
3345
3402
  if (info.hasArchitecture) {
3346
- const archPath = join6(cwd, "ARCHITECTURE.md");
3347
- const parser = new ArchitectureParser(archPath);
3403
+ const archInfo = resolveArchitecturePath(cwd);
3404
+ if (!archInfo.path) {
3405
+ return info;
3406
+ }
3407
+ const parser = new ArchitectureParser(archInfo.path);
3348
3408
  const result = await parser.parse();
3349
3409
  if (result.success && result.schema) {
3350
3410
  info.posture = result.schema.qualityLevel?.posture;
@@ -3355,7 +3415,7 @@ async function gatherProjectInfo(cwd) {
3355
3415
  return info;
3356
3416
  }
3357
3417
  async function runConversationalInterview(cwd, initialMessage) {
3358
- const { InterviewerAgent, createInterviewerAgent } = await import("./interviewer-NQHNMVH4.js");
3418
+ const { InterviewerAgent, createInterviewerAgent } = await import("./interviewer-BWM5SNOE.js");
3359
3419
  const agent = await createInterviewerAgent();
3360
3420
  if (agent && agent.isAvailable()) {
3361
3421
  await runAIInterview(cwd, initialMessage, agent);
@@ -3506,7 +3566,7 @@ ${state.forbiddenPatterns?.length ? `- **Forbidden patterns:** ${state.forbidden
3506
3566
  if (continueChoice) {
3507
3567
  const description = await prompt("Describe what you want to build first");
3508
3568
  if (description.trim()) {
3509
- const { plan: plan2 } = await import("./plan-4RIHWWZG.js");
3569
+ const { plan: plan2 } = await import("./plan-HCYXLSSD.js");
3510
3570
  await plan2(description, {});
3511
3571
  }
3512
3572
  }
@@ -3544,7 +3604,7 @@ async function handleAdaptExisting(cwd, state) {
3544
3604
  console.log(chalk6.dim("I can analyze your codebase and adapt the governance files to match your structure."));
3545
3605
  console.log(chalk6.dim("This helps me understand your architecture without changing any code.\n"));
3546
3606
  }
3547
- const response = await promptWithCommands("What would you like to do?");
3607
+ const response = await promptWithCommands("What would you like to do?", { allowMultiline: true });
3548
3608
  if (response.toLowerCase() === "q" || response.toLowerCase() === "quit") {
3549
3609
  process.exit(0);
3550
3610
  }
@@ -3560,7 +3620,7 @@ async function handleAdaptExisting(cwd, state) {
3560
3620
  }
3561
3621
  if (intent.mode === "ad_hoc" && intent.confidence >= 0.7) {
3562
3622
  console.log(chalk6.dim("\n> Got it! Creating a task for this...\n"));
3563
- const { plan: plan2 } = await import("./plan-4RIHWWZG.js");
3623
+ const { plan: plan2 } = await import("./plan-HCYXLSSD.js");
3564
3624
  await plan2(response, {});
3565
3625
  return;
3566
3626
  }
@@ -3591,7 +3651,7 @@ async function showAdaptExistingMenu(cwd, state) {
3591
3651
  case "2": {
3592
3652
  const description = await prompt("Describe what you want to do");
3593
3653
  if (description.trim()) {
3594
- const { plan: plan2 } = await import("./plan-4RIHWWZG.js");
3654
+ const { plan: plan2 } = await import("./plan-HCYXLSSD.js");
3595
3655
  await plan2(description, {});
3596
3656
  }
3597
3657
  break;
@@ -3643,7 +3703,7 @@ async function analyzeAndAdapt(cwd) {
3643
3703
  async function codeReviewFirst(cwd) {
3644
3704
  console.log(chalk6.blue("\n-- Code Review Mode --\n"));
3645
3705
  console.log(chalk6.dim("I'll analyze your code for issues without making any changes.\n"));
3646
- const { reviewInit: reviewInit2, reviewAnalyze: reviewAnalyze2, reviewRun: reviewRun2 } = await import("./review-AUG6GIL6.js");
3706
+ const { reviewInit: reviewInit2, reviewAnalyze: reviewAnalyze2, reviewRun: reviewRun2 } = await import("./review-F6DHAGDF.js");
3647
3707
  const reviewDbPath = join6(cwd, "docs", "code-review", "review-tasks.db");
3648
3708
  if (!existsSync6(reviewDbPath)) {
3649
3709
  await reviewInit2();
@@ -3679,6 +3739,14 @@ async function handleContinueSession(cwd, state) {
3679
3739
  }
3680
3740
  function checkForHandoff(cwd) {
3681
3741
  try {
3742
+ const currentContextPath = join6(cwd, ".archon", "current_context.md");
3743
+ if (existsSync6(currentContextPath)) {
3744
+ const content2 = readFileSync3(currentContextPath, "utf-8");
3745
+ const nextStepsMatch = content2.match(/## Next Actions[^\n]*\n([\s\S]*?)(?=\n## |\n*$)/);
3746
+ if (nextStepsMatch && nextStepsMatch[1]) {
3747
+ return { nextSteps: nextStepsMatch[1].trim() };
3748
+ }
3749
+ }
3682
3750
  const progressPath = join6(cwd, "progress.txt");
3683
3751
  if (!existsSync6(progressPath)) return null;
3684
3752
  const content = readFileSync3(progressPath, "utf-8");
@@ -3742,7 +3810,7 @@ async function showMainMenu() {
3742
3810
  }
3743
3811
  async function showReviewProgress(cwd) {
3744
3812
  try {
3745
- const { ReviewDatabase } = await import("./code-review-6MU4UE5M.js");
3813
+ const { ReviewDatabase } = await import("./code-review-ODLXGXNZ.js");
3746
3814
  const db = new ReviewDatabase(cwd);
3747
3815
  db.open();
3748
3816
  const stats = db.getStats();
@@ -3759,18 +3827,18 @@ async function showReviewProgress(cwd) {
3759
3827
  }
3760
3828
  }
3761
3829
  async function planTask() {
3762
- const { plan: plan2 } = await import("./plan-4RIHWWZG.js");
3830
+ const { plan: plan2 } = await import("./plan-HCYXLSSD.js");
3763
3831
  const description = await prompt("Describe what you want to build");
3764
3832
  if (description.trim()) {
3765
3833
  await plan2(description, {});
3766
3834
  }
3767
3835
  }
3768
3836
  async function listAtoms() {
3769
- const { list: list2 } = await import("./list-BJCKDRG4.js");
3837
+ const { list: list2 } = await import("./list-REPLUXJF.js");
3770
3838
  await list2({});
3771
3839
  }
3772
3840
  async function executeNext() {
3773
- const { listLocalAtoms: listLocalAtoms2 } = await import("./plan-4RIHWWZG.js");
3841
+ const { listLocalAtoms: listLocalAtoms2 } = await import("./plan-HCYXLSSD.js");
3774
3842
  const { analyzeProject, getComplexityDescription, getModeDescription } = await import("./orchestration-HIF3KP25.js");
3775
3843
  const { loadExecutionPreferences } = await import("./preferences-I6WETXOI.js");
3776
3844
  const cwd = process.cwd();
@@ -3841,11 +3909,11 @@ async function executeNext() {
3841
3909
  }
3842
3910
  }
3843
3911
  if (selectedMode === "parallel-cloud") {
3844
- const { parallelExecuteCloud: parallelExecuteCloud2 } = await import("./parallel-U3COBCHB.js");
3912
+ const { parallelExecuteCloud: parallelExecuteCloud2 } = await import("./parallel-23VQYK7H.js");
3845
3913
  await parallelExecuteCloud2(runIds);
3846
3914
  return;
3847
3915
  }
3848
- const { parallelExecute } = await import("./parallel-U3COBCHB.js");
3916
+ const { parallelExecute } = await import("./parallel-23VQYK7H.js");
3849
3917
  await parallelExecute(runIds);
3850
3918
  return;
3851
3919
  }
@@ -3853,14 +3921,14 @@ async function executeNext() {
3853
3921
  const atomId = await prompt("Enter atom ID to execute (or press Enter for first pending)");
3854
3922
  const targetId = atomId.trim() || pendingAtoms[0]?.id;
3855
3923
  if (targetId) {
3856
- const { execute: execute2 } = await import("./execute-OTW55P2Q.js");
3924
+ const { execute: execute2 } = await import("./execute-ZTJGSRBW.js");
3857
3925
  await execute2(targetId, {});
3858
3926
  } else {
3859
3927
  console.log(chalk6.yellow("No atom to execute."));
3860
3928
  }
3861
3929
  }
3862
3930
  async function reportBug() {
3863
- const { bugReport: bugReport2 } = await import("./bug-DCFTT2AF.js");
3931
+ const { bugReport: bugReport2 } = await import("./bug-IJCK43FK.js");
3864
3932
  const title = await prompt("Bug title");
3865
3933
  if (title.trim()) {
3866
3934
  await bugReport2(title, {});
@@ -3880,7 +3948,7 @@ async function reviewCode() {
3880
3948
  const reviewDbPath = join6(cwd, "docs", "code-review", "review-tasks.db");
3881
3949
  if (!existsSync6(reviewDbPath)) {
3882
3950
  console.log(chalk6.dim("Code review not initialized. Starting setup...\n"));
3883
- const { reviewInit: reviewInit2 } = await import("./review-AUG6GIL6.js");
3951
+ const { reviewInit: reviewInit2 } = await import("./review-F6DHAGDF.js");
3884
3952
  await reviewInit2();
3885
3953
  console.log();
3886
3954
  }
@@ -3895,27 +3963,27 @@ async function reviewCode() {
3895
3963
  const choice = await prompt("Enter choice");
3896
3964
  switch (choice.toLowerCase()) {
3897
3965
  case "1": {
3898
- const { reviewAnalyze: reviewAnalyze2 } = await import("./review-AUG6GIL6.js");
3966
+ const { reviewAnalyze: reviewAnalyze2 } = await import("./review-F6DHAGDF.js");
3899
3967
  await reviewAnalyze2();
3900
3968
  break;
3901
3969
  }
3902
3970
  case "2": {
3903
- const { reviewStatus: reviewStatus2 } = await import("./review-AUG6GIL6.js");
3971
+ const { reviewStatus: reviewStatus2 } = await import("./review-F6DHAGDF.js");
3904
3972
  await reviewStatus2();
3905
3973
  break;
3906
3974
  }
3907
3975
  case "3": {
3908
- const { reviewNext: reviewNext2 } = await import("./review-AUG6GIL6.js");
3976
+ const { reviewNext: reviewNext2 } = await import("./review-F6DHAGDF.js");
3909
3977
  await reviewNext2();
3910
3978
  break;
3911
3979
  }
3912
3980
  case "4": {
3913
- const { reviewList: reviewList2 } = await import("./review-AUG6GIL6.js");
3981
+ const { reviewList: reviewList2 } = await import("./review-F6DHAGDF.js");
3914
3982
  await reviewList2({});
3915
3983
  break;
3916
3984
  }
3917
3985
  case "5": {
3918
- const { reviewRun: reviewRun2 } = await import("./review-AUG6GIL6.js");
3986
+ const { reviewRun: reviewRun2 } = await import("./review-F6DHAGDF.js");
3919
3987
  await reviewRun2({ all: true });
3920
3988
  break;
3921
3989
  }
@@ -3973,9 +4041,41 @@ function prompt(question) {
3973
4041
  });
3974
4042
  });
3975
4043
  }
3976
- async function promptWithCommands(question) {
4044
+ function promptMultiline(question, idleMs = 250) {
4045
+ return new Promise((resolve) => {
4046
+ const rl = readline.createInterface({
4047
+ input: process.stdin,
4048
+ output: process.stdout
4049
+ });
4050
+ const lines = [];
4051
+ let timer = null;
4052
+ const finish = () => {
4053
+ if (timer) clearTimeout(timer);
4054
+ rl.close();
4055
+ resolve(lines.join("\n").trimEnd());
4056
+ };
4057
+ const scheduleFinish = () => {
4058
+ if (timer) clearTimeout(timer);
4059
+ timer = setTimeout(finish, idleMs);
4060
+ };
4061
+ rl.on("line", (line) => {
4062
+ lines.push(line);
4063
+ scheduleFinish();
4064
+ });
4065
+ rl.on("SIGINT", () => {
4066
+ rl.close();
4067
+ process.exit(0);
4068
+ });
4069
+ rl.setPrompt(`${chalk6.cyan("?")} ${question}: `);
4070
+ rl.prompt();
4071
+ });
4072
+ }
4073
+ async function promptWithCommands(question, options = {}) {
3977
4074
  while (true) {
3978
- const answer = await prompt(question);
4075
+ const answer = options.allowMultiline ? await promptMultiline(question) : await prompt(question);
4076
+ if (options.allowMultiline && answer.includes("\n")) {
4077
+ return answer;
4078
+ }
3979
4079
  const handled = await handleInSessionCommand(answer);
3980
4080
  if (!handled) {
3981
4081
  return answer;
@@ -3986,7 +4086,7 @@ async function promptWithCommands(question) {
3986
4086
  async function runWebChecksSuite() {
3987
4087
  const { a11yCheck: a11yCheck2 } = await import("./a11y-O35BAA25.js");
3988
4088
  const { seoCheck } = await import("./seo-PMI42KRZ.js");
3989
- const { geoAudit } = await import("./geo-GEWH777F.js");
4089
+ const { geoAudit } = await import("./geo-HRG7M7YX.js");
3990
4090
  console.log(chalk6.blue("\nRunning web checks (A11y, SEO, GEO)...\n"));
3991
4091
  await a11yCheck2({});
3992
4092
  await seoCheck({});
@@ -4026,17 +4126,17 @@ async function showWebChecksMenu() {
4026
4126
  break;
4027
4127
  }
4028
4128
  case "4": {
4029
- const { geoAudit } = await import("./geo-GEWH777F.js");
4129
+ const { geoAudit } = await import("./geo-HRG7M7YX.js");
4030
4130
  await geoAudit();
4031
4131
  break;
4032
4132
  }
4033
4133
  case "5": {
4034
- const { geoIdentity } = await import("./geo-GEWH777F.js");
4134
+ const { geoIdentity } = await import("./geo-HRG7M7YX.js");
4035
4135
  await geoIdentity();
4036
4136
  break;
4037
4137
  }
4038
4138
  case "6": {
4039
- const { geoSchema } = await import("./geo-GEWH777F.js");
4139
+ const { geoSchema } = await import("./geo-HRG7M7YX.js");
4040
4140
  await geoSchema({});
4041
4141
  break;
4042
4142
  }
@@ -4172,9 +4272,9 @@ async function showCredits() {
4172
4272
  console.log(chalk7.dim(" Using your own API keys - no credit charges"));
4173
4273
  }
4174
4274
  console.log();
4175
- } catch (err) {
4275
+ } catch (err2) {
4176
4276
  spinner.fail("Error fetching credits");
4177
- console.error(err);
4277
+ console.error(err2);
4178
4278
  }
4179
4279
  }
4180
4280
  async function addCredits(options = {}) {
@@ -4228,9 +4328,9 @@ async function addCredits(options = {}) {
4228
4328
  } catch {
4229
4329
  console.log(chalk7.yellow(" Could not open browser. Please visit the URL above."));
4230
4330
  }
4231
- } catch (err) {
4331
+ } catch (err2) {
4232
4332
  spinner.fail("Error preparing checkout");
4233
- console.error(err);
4333
+ console.error(err2);
4234
4334
  }
4235
4335
  }
4236
4336
  async function showHistory(options = {}) {
@@ -4274,9 +4374,9 @@ async function showHistory(options = {}) {
4274
4374
  ` ${"Total".padEnd(30)} ${totalTokens.toString().padStart(8)} ${chalk7.green(`$${totalCost.toFixed(4)}`.padStart(10))}`
4275
4375
  );
4276
4376
  console.log();
4277
- } catch (err) {
4377
+ } catch (err2) {
4278
4378
  spinner.fail("Error fetching history");
4279
- console.error(err);
4379
+ console.error(err2);
4280
4380
  }
4281
4381
  }
4282
4382
  async function manageBudget(options = {}) {
@@ -4356,9 +4456,9 @@ async function manageBudget(options = {}) {
4356
4456
  console.log(chalk7.dim(" Clear budget: archon credits budget --clear"));
4357
4457
  console.log(chalk7.dim(" Set alert: archon credits budget --alert 80"));
4358
4458
  console.log();
4359
- } catch (err) {
4459
+ } catch (err2) {
4360
4460
  spinner.fail("Error managing budget");
4361
- console.error(err);
4461
+ console.error(err2);
4362
4462
  }
4363
4463
  }
4364
4464
  async function manageAutoRecharge(options = {}) {
@@ -4434,9 +4534,9 @@ async function manageAutoRecharge(options = {}) {
4434
4534
  console.log(chalk7.dim(" Enable: archon credits auto-recharge --enable --threshold 5 --amount 20"));
4435
4535
  console.log(chalk7.dim(" Disable: archon credits auto-recharge --disable"));
4436
4536
  console.log();
4437
- } catch (err) {
4537
+ } catch (err2) {
4438
4538
  spinner.fail("Error managing auto-recharge");
4439
- console.error(err);
4539
+ console.error(err2);
4440
4540
  }
4441
4541
  }
4442
4542
  async function showAuditHistory(options = {}) {
@@ -4489,9 +4589,9 @@ async function showAuditHistory(options = {}) {
4489
4589
  console.log(chalk7.dim(` Showing ${history.length} most recent events`));
4490
4590
  console.log(chalk7.dim(" Use --limit N to show more"));
4491
4591
  console.log();
4492
- } catch (err) {
4592
+ } catch (err2) {
4493
4593
  spinner.fail("Error fetching audit history");
4494
- console.error(err);
4594
+ console.error(err2);
4495
4595
  }
4496
4596
  }
4497
4597
  function formatEventType(eventType) {
@@ -5149,9 +5249,9 @@ async function saveSession(name) {
5149
5249
  console.log();
5150
5250
  console.log(chalk9.dim(" Resume on another device: archon session resume " + session.id));
5151
5251
  console.log();
5152
- } catch (err) {
5252
+ } catch (err2) {
5153
5253
  spinner.fail("Error saving session");
5154
- console.error(err);
5254
+ console.error(err2);
5155
5255
  }
5156
5256
  }
5157
5257
  async function listSessions() {
@@ -5192,9 +5292,9 @@ async function listSessions() {
5192
5292
  console.log();
5193
5293
  }
5194
5294
  console.log(chalk9.dim(" Resume: archon session resume <id>\n"));
5195
- } catch (err) {
5295
+ } catch (err2) {
5196
5296
  spinner.fail("Error fetching sessions");
5197
- console.error(err);
5297
+ console.error(err2);
5198
5298
  }
5199
5299
  }
5200
5300
  async function resumeSession(sessionId) {
@@ -5243,9 +5343,9 @@ async function resumeSession(sessionId) {
5243
5343
  console.log();
5244
5344
  console.log(chalk9.dim(" Continue working: archon start"));
5245
5345
  console.log();
5246
- } catch (err) {
5346
+ } catch (err2) {
5247
5347
  spinner.fail("Error resuming session");
5248
- console.error(err);
5348
+ console.error(err2);
5249
5349
  }
5250
5350
  }
5251
5351
  async function syncSession() {
@@ -5285,9 +5385,9 @@ async function syncSession() {
5285
5385
  return;
5286
5386
  }
5287
5387
  spinner.succeed(chalk9.green("Session synced to cloud"));
5288
- } catch (err) {
5388
+ } catch (err2) {
5289
5389
  spinner.fail("Error syncing session");
5290
- console.error(err);
5390
+ console.error(err2);
5291
5391
  }
5292
5392
  }
5293
5393
 
@@ -6321,9 +6421,9 @@ async function interview(options = {}) {
6321
6421
  console.log(` ${chalk13.cyan("2.")} Run ${chalk13.bold("archon list")} to see generated atoms`);
6322
6422
  console.log(` ${chalk13.cyan("3.")} Run ${chalk13.bold("archon execute <atom-id>")} to start building`);
6323
6423
  console.log();
6324
- } catch (err) {
6424
+ } catch (err2) {
6325
6425
  spinner.fail("Failed to freeze Constitution");
6326
- console.error(err);
6426
+ console.error(err2);
6327
6427
  }
6328
6428
  }
6329
6429
  async function runPhase(phase, constitution, cwd) {
@@ -7002,13 +7102,13 @@ async function modelsSync(options) {
7002
7102
  if (result.parseErrors.length > 0) {
7003
7103
  console.log();
7004
7104
  console.log(chalk16.red(`\u26A0\uFE0F Warnings/Errors (${result.parseErrors.length}):`));
7005
- for (const err of result.parseErrors) {
7006
- console.log(chalk16.red(` - ${err}`));
7105
+ for (const err2 of result.parseErrors) {
7106
+ console.log(chalk16.red(` - ${err2}`));
7007
7107
  }
7008
7108
  }
7009
7109
  console.log();
7010
- } catch (err) {
7011
- console.log(chalk16.red(`Failed to run sync: ${err}`));
7110
+ } catch (err2) {
7111
+ console.log(chalk16.red(`Failed to run sync: ${err2}`));
7012
7112
  }
7013
7113
  }
7014
7114
  async function modelsList() {
@@ -7035,13 +7135,766 @@ async function modelsList() {
7035
7135
  console.log();
7036
7136
  }
7037
7137
 
7138
+ // src/cli/governance.ts
7139
+ import { Command as Command2 } from "commander";
7140
+ import chalk17 from "chalk";
7141
+ import { existsSync as existsSync18, readFileSync as readFileSync6 } from "fs";
7142
+ import { readFile as readFile12 } from "fs/promises";
7143
+ import { join as join19 } from "path";
7144
+ import matter4 from "gray-matter";
7145
+
7146
+ // src/core/governance/store.ts
7147
+ import { existsSync as existsSync16, mkdirSync as mkdirSync3 } from "fs";
7148
+ import { readFile as readFile10, writeFile as writeFile8, appendFile, unlink as unlink2, stat as stat2, rename } from "fs/promises";
7149
+ import { join as join16 } from "path";
7150
+ import matter from "gray-matter";
7151
+ var ARCHON_DIR2 = ".archon";
7152
+ var ACTIVE_DIR = join16(ARCHON_DIR2, "active");
7153
+ var HISTORY_DIR = join16(ARCHON_DIR2, "history");
7154
+ var ARCHIVE_DIR2 = join16(ARCHON_DIR2, "archive");
7155
+ var LOCK_FILE = join16(ARCHON_DIR2, "governance.lock");
7156
+ var CURRENT_CONTEXT = join16(ARCHON_DIR2, "current_context.md");
7157
+ var ARCHITECTURE_FILE = join16(ACTIVE_DIR, "architecture.md");
7158
+ var TASKS_FILE = join16(ACTIVE_DIR, "tasks.json");
7159
+ var HANDOFFS_FILE = join16(HISTORY_DIR, "handoffs.jsonl");
7160
+ var DECISION_LOG_FILE = join16(HISTORY_DIR, "decision_log.jsonl");
7161
+ var COMPLETED_TASKS_FILE = join16(ARCHIVE_DIR2, "completed_tasks.jsonl");
7162
+ var DEFAULT_LOCK_TIMEOUT_MS = 5e3;
7163
+ var DEFAULT_LOCK_RETRY_MS = 100;
7164
+ var DEFAULT_STALE_LOCK_MS = 2 * 60 * 1e3;
7165
+ var GovernanceStore = class {
7166
+ cwd;
7167
+ constructor(cwd = process.cwd()) {
7168
+ this.cwd = cwd;
7169
+ }
7170
+ /**
7171
+ * Ensure governance directories exist
7172
+ */
7173
+ ensureStructure() {
7174
+ this.ensureDir(join16(this.cwd, ARCHON_DIR2));
7175
+ this.ensureDir(join16(this.cwd, ACTIVE_DIR));
7176
+ this.ensureDir(join16(this.cwd, HISTORY_DIR));
7177
+ this.ensureDir(join16(this.cwd, ARCHIVE_DIR2));
7178
+ }
7179
+ /**
7180
+ * Read current architecture content (without frontmatter)
7181
+ */
7182
+ async readArchitecture() {
7183
+ const filePath = join16(this.cwd, ARCHITECTURE_FILE);
7184
+ if (!existsSync16(filePath)) {
7185
+ return ok("");
7186
+ }
7187
+ try {
7188
+ const raw = await readFile10(filePath, "utf-8");
7189
+ const parsed = matter(raw);
7190
+ return ok(parsed.content.trim());
7191
+ } catch (error) {
7192
+ return err(error instanceof Error ? error.message : "Failed to read architecture");
7193
+ }
7194
+ }
7195
+ /**
7196
+ * Update architecture with required change_reason and optional updated_by
7197
+ */
7198
+ async updateArchitecture(content, changeReason, updatedBy) {
7199
+ if (!changeReason.trim()) {
7200
+ return err("change_reason is required for architecture updates");
7201
+ }
7202
+ this.ensureStructure();
7203
+ const release = await this.acquireLock();
7204
+ if (!release.ok) return release;
7205
+ try {
7206
+ const now = (/* @__PURE__ */ new Date()).toISOString();
7207
+ const filePath = join16(this.cwd, ARCHITECTURE_FILE);
7208
+ const current = await this.readArchitectureFrontmatter(filePath);
7209
+ const nextVersion = this.nextVersion(current?.version);
7210
+ const frontmatter = {
7211
+ version: nextVersion,
7212
+ last_updated: now,
7213
+ change_reason: changeReason
7214
+ };
7215
+ if (updatedBy) {
7216
+ frontmatter.updated_by = updatedBy;
7217
+ }
7218
+ const output = matter.stringify(content.trim() + "\n", frontmatter);
7219
+ await this.writeFileAtomic(filePath, output);
7220
+ const decision = {
7221
+ timestamp: now,
7222
+ category: "architecture",
7223
+ change_reason: changeReason,
7224
+ updated_by: updatedBy
7225
+ };
7226
+ await this.appendJsonLine(join16(this.cwd, DECISION_LOG_FILE), decision);
7227
+ return ok(void 0);
7228
+ } catch (error) {
7229
+ return err(error instanceof Error ? error.message : "Failed to update architecture");
7230
+ } finally {
7231
+ await release.value();
7232
+ }
7233
+ }
7234
+ /**
7235
+ * Update a task's status and optional notes. Moves to archive when done.
7236
+ */
7237
+ async updateTask(taskId, status2, notes) {
7238
+ this.ensureStructure();
7239
+ const release = await this.acquireLock();
7240
+ if (!release.ok) return release;
7241
+ try {
7242
+ const tasksPath = join16(this.cwd, TASKS_FILE);
7243
+ const tasks = await this.loadTasks(tasksPath);
7244
+ if (!tasks.ok) return tasks;
7245
+ const index = tasks.value.findIndex((task2) => task2.id === taskId);
7246
+ if (index === -1) {
7247
+ return err(`Task not found: ${taskId}`);
7248
+ }
7249
+ const now = (/* @__PURE__ */ new Date()).toISOString();
7250
+ const task = { ...tasks.value[index] };
7251
+ task.status = status2;
7252
+ task.notes = notes ?? task.notes;
7253
+ task.updated_at = now;
7254
+ if (status2 === "done") {
7255
+ tasks.value.splice(index, 1);
7256
+ await this.appendJsonLine(join16(this.cwd, COMPLETED_TASKS_FILE), task);
7257
+ } else {
7258
+ tasks.value[index] = task;
7259
+ }
7260
+ await this.writeJson(tasksPath, tasks.value);
7261
+ return ok(void 0);
7262
+ } catch (error) {
7263
+ return err(error instanceof Error ? error.message : "Failed to update task");
7264
+ } finally {
7265
+ await release.value();
7266
+ }
7267
+ }
7268
+ /**
7269
+ * Append handoff entry and update current_context.md
7270
+ */
7271
+ async logHandoff(entry) {
7272
+ if (!entry.reason.trim()) {
7273
+ return err("reason is required for handoff");
7274
+ }
7275
+ if (!entry.summary.trim()) {
7276
+ return err("summary is required for handoff");
7277
+ }
7278
+ if (!entry.next_actions || entry.next_actions.length === 0) {
7279
+ return err("next_actions are required for handoff");
7280
+ }
7281
+ this.ensureStructure();
7282
+ const release = await this.acquireLock();
7283
+ if (!release.ok) return release;
7284
+ try {
7285
+ await this.appendJsonLine(join16(this.cwd, HANDOFFS_FILE), entry);
7286
+ const contextLines = [
7287
+ "# Current Context",
7288
+ "",
7289
+ `Timestamp: ${entry.timestamp}`,
7290
+ entry.from_agent ? `From: ${entry.from_agent}` : void 0,
7291
+ `Reason: ${entry.reason}`,
7292
+ "",
7293
+ "## Summary",
7294
+ entry.summary.trim(),
7295
+ "",
7296
+ "## Next Actions",
7297
+ ...entry.next_actions.map((action) => `- ${action}`),
7298
+ ""
7299
+ ].filter((line) => typeof line === "string");
7300
+ await this.writeFileAtomic(join16(this.cwd, CURRENT_CONTEXT), contextLines.join("\n"));
7301
+ return ok(void 0);
7302
+ } catch (error) {
7303
+ return err(error instanceof Error ? error.message : "Failed to log handoff");
7304
+ } finally {
7305
+ await release.value();
7306
+ }
7307
+ }
7308
+ ensureDir(path2) {
7309
+ if (!existsSync16(path2)) {
7310
+ mkdirSync3(path2, { recursive: true });
7311
+ }
7312
+ }
7313
+ async acquireLock(timeoutMs = DEFAULT_LOCK_TIMEOUT_MS, retryMs = DEFAULT_LOCK_RETRY_MS, staleMs = DEFAULT_STALE_LOCK_MS) {
7314
+ const lockPath = join16(this.cwd, LOCK_FILE);
7315
+ const deadline = Date.now() + timeoutMs;
7316
+ while (Date.now() < deadline) {
7317
+ try {
7318
+ await this.tryCreateLock(lockPath);
7319
+ return ok(async () => {
7320
+ await this.safeUnlink(lockPath);
7321
+ });
7322
+ } catch (error) {
7323
+ if (error instanceof Error && error.message === "LOCK_EXISTS") {
7324
+ const staleCleared = await this.clearStaleLock(lockPath, staleMs);
7325
+ if (staleCleared) {
7326
+ continue;
7327
+ }
7328
+ await sleep(retryMs);
7329
+ continue;
7330
+ }
7331
+ return err("Failed to acquire governance lock");
7332
+ }
7333
+ }
7334
+ return err("Timed out waiting for governance lock");
7335
+ }
7336
+ async tryCreateLock(lockPath) {
7337
+ if (existsSync16(lockPath)) {
7338
+ throw new Error("LOCK_EXISTS");
7339
+ }
7340
+ const payload = JSON.stringify({ pid: process.pid, created_at: (/* @__PURE__ */ new Date()).toISOString() });
7341
+ await writeFile8(lockPath, payload, { flag: "wx" });
7342
+ }
7343
+ async clearStaleLock(lockPath, staleMs) {
7344
+ try {
7345
+ const info = await stat2(lockPath);
7346
+ const ageByMtime = Date.now() - info.mtimeMs;
7347
+ let ageByCreatedAt = null;
7348
+ try {
7349
+ const raw = await readFile10(lockPath, "utf-8");
7350
+ const parsed = JSON.parse(raw);
7351
+ if (parsed.created_at) {
7352
+ const createdAt = Date.parse(parsed.created_at);
7353
+ if (!Number.isNaN(createdAt)) {
7354
+ ageByCreatedAt = Date.now() - createdAt;
7355
+ }
7356
+ }
7357
+ } catch {
7358
+ }
7359
+ const ageMs = Math.max(ageByMtime, ageByCreatedAt ?? -Infinity);
7360
+ if (ageMs > staleMs) {
7361
+ await this.safeUnlink(lockPath);
7362
+ return true;
7363
+ }
7364
+ } catch {
7365
+ return false;
7366
+ }
7367
+ return false;
7368
+ }
7369
+ async safeUnlink(path2) {
7370
+ try {
7371
+ await unlink2(path2);
7372
+ } catch {
7373
+ }
7374
+ }
7375
+ async readArchitectureFrontmatter(filePath) {
7376
+ if (!existsSync16(filePath)) return null;
7377
+ const raw = await readFile10(filePath, "utf-8");
7378
+ const parsed = matter(raw);
7379
+ const data = parsed.data;
7380
+ const versionRaw = data["version"];
7381
+ const version = typeof versionRaw === "number" ? versionRaw : typeof versionRaw === "string" ? Number.parseFloat(versionRaw) : 1;
7382
+ return {
7383
+ version: Number.isFinite(version) ? version : 1,
7384
+ last_updated: typeof data["last_updated"] === "string" ? data["last_updated"] : "",
7385
+ updated_by: typeof data["updated_by"] === "string" ? data["updated_by"] : void 0,
7386
+ change_reason: typeof data["change_reason"] === "string" ? data["change_reason"] : ""
7387
+ };
7388
+ }
7389
+ nextVersion(current) {
7390
+ if (!current || !Number.isFinite(current)) return 1;
7391
+ return Math.round((current + 0.1) * 10) / 10;
7392
+ }
7393
+ async loadTasks(path2) {
7394
+ if (!existsSync16(path2)) return ok([]);
7395
+ try {
7396
+ const raw = await readFile10(path2, "utf-8");
7397
+ const data = JSON.parse(raw);
7398
+ if (!Array.isArray(data)) {
7399
+ return err("tasks.json must be an array");
7400
+ }
7401
+ const parsed = [];
7402
+ for (const item of data) {
7403
+ const task = this.parseTask(item);
7404
+ if (!task) {
7405
+ return err("tasks.json contains invalid entries");
7406
+ }
7407
+ parsed.push(task);
7408
+ }
7409
+ return ok(parsed);
7410
+ } catch (error) {
7411
+ return err(error instanceof Error ? error.message : "Failed to parse tasks.json");
7412
+ }
7413
+ }
7414
+ parseTask(value) {
7415
+ if (typeof value !== "object" || value === null) return null;
7416
+ const raw = value;
7417
+ const id = typeof raw["id"] === "string" ? raw["id"] : null;
7418
+ const description = typeof raw["description"] === "string" ? raw["description"] : null;
7419
+ const status2 = this.parseStatus(raw["status"]);
7420
+ const createdAt = typeof raw["created_at"] === "string" ? raw["created_at"] : null;
7421
+ if (!id || !description || !status2 || !createdAt) return null;
7422
+ return {
7423
+ id,
7424
+ parent_id: typeof raw["parent_id"] === "string" ? raw["parent_id"] : void 0,
7425
+ description,
7426
+ status: status2,
7427
+ assigned_to: typeof raw["assigned_to"] === "string" ? raw["assigned_to"] : void 0,
7428
+ created_at: createdAt,
7429
+ updated_at: typeof raw["updated_at"] === "string" ? raw["updated_at"] : void 0,
7430
+ notes: typeof raw["notes"] === "string" ? raw["notes"] : void 0
7431
+ };
7432
+ }
7433
+ parseStatus(value) {
7434
+ if (value === "pending" || value === "in_progress" || value === "verification" || value === "done") {
7435
+ return value;
7436
+ }
7437
+ return null;
7438
+ }
7439
+ async writeJson(path2, payload) {
7440
+ const content = JSON.stringify(payload, null, 2) + "\n";
7441
+ await this.writeFileAtomic(path2, content);
7442
+ }
7443
+ async writeFileAtomic(path2, content) {
7444
+ const tmpPath = `${path2}.tmp`;
7445
+ await writeFile8(tmpPath, content, "utf-8");
7446
+ try {
7447
+ await rename(tmpPath, path2);
7448
+ } catch {
7449
+ await this.safeUnlink(path2);
7450
+ await rename(tmpPath, path2);
7451
+ }
7452
+ }
7453
+ async appendJsonLine(path2, payload) {
7454
+ const line = JSON.stringify(payload) + "\n";
7455
+ await appendFile(path2, line, "utf-8");
7456
+ }
7457
+ };
7458
+
7459
+ // src/core/governance/migrate.ts
7460
+ import { existsSync as existsSync17, mkdirSync as mkdirSync4 } from "fs";
7461
+ import { readFile as readFile11, writeFile as writeFile9, unlink as unlink3 } from "fs/promises";
7462
+ import { join as join17 } from "path";
7463
+ import matter2 from "gray-matter";
7464
+ var LEGACY_ARCH_PATH = "ARCHITECTURE.md";
7465
+ var LEGACY_TASKS_PATH = join17(".archon", "current-tasks.md");
7466
+ var ACTIVE_ARCH_PATH2 = join17(".archon", "active", "architecture.md");
7467
+ var ACTIVE_TASKS_PATH = join17(".archon", "active", "tasks.json");
7468
+ var ARCHIVE_COMPLETED_PATH = join17(".archon", "archive", "completed_tasks.jsonl");
7469
+ var HISTORY_LEGACY_DIR = join17(".archon", "history", "legacy");
7470
+ function parseLegacyTasks(content) {
7471
+ const result = { active: [], paused: [] };
7472
+ const activeHeaderMatch = content.match(/##\s+Active\s*\((\d{4}-\d{2}-\d{2})\)/i);
7473
+ if (activeHeaderMatch?.[1]) {
7474
+ result.referenceDate = activeHeaderMatch[1];
7475
+ }
7476
+ const sections = content.split(/\n##\s+/).map((block) => block.trim());
7477
+ for (const section of sections) {
7478
+ const normalized = section.toLowerCase();
7479
+ const lines = section.split("\n").slice(1);
7480
+ if (normalized.startsWith("active")) {
7481
+ for (const line of lines) {
7482
+ const match = line.match(/^\d+\.\s+(.*)$/);
7483
+ if (!match?.[1]) continue;
7484
+ const raw = match[1].trim();
7485
+ if (!raw) continue;
7486
+ const done = /\(done\)\s*$/i.test(raw);
7487
+ const cleaned = raw.replace(/\s*\(done\)\s*$/i, "").trim();
7488
+ result.active.push({ description: cleaned, done });
7489
+ }
7490
+ }
7491
+ if (normalized.startsWith("paused")) {
7492
+ for (const line of lines) {
7493
+ const match = line.match(/^\d+\.\s+(.*)$/);
7494
+ if (!match?.[1]) continue;
7495
+ const raw = match[1].trim();
7496
+ if (!raw) continue;
7497
+ result.paused.push(raw);
7498
+ }
7499
+ }
7500
+ }
7501
+ return result;
7502
+ }
7503
+ function buildTaskEntries(parsed, nowIso) {
7504
+ const active = [];
7505
+ const completed = [];
7506
+ let counter = 1;
7507
+ const referenceDate = parsed.referenceDate ? `${parsed.referenceDate}T00:00:00.000Z` : nowIso;
7508
+ const makeTask = (description, status2, notes) => {
7509
+ const task = {
7510
+ id: `TASK-${String(counter).padStart(3, "0")}`,
7511
+ description,
7512
+ status: status2,
7513
+ created_at: referenceDate,
7514
+ updated_at: nowIso,
7515
+ notes
7516
+ };
7517
+ counter += 1;
7518
+ return task;
7519
+ };
7520
+ for (const item of parsed.active) {
7521
+ if (item.done) {
7522
+ completed.push(makeTask(item.description, "done", "Migrated from current-tasks.md (done)"));
7523
+ } else {
7524
+ active.push(makeTask(item.description, "pending"));
7525
+ }
7526
+ }
7527
+ for (const paused of parsed.paused) {
7528
+ active.push(makeTask(paused, "pending", "Migrated from current-tasks.md (paused)"));
7529
+ }
7530
+ return { active, completed };
7531
+ }
7532
+ async function writeJson(path2, payload, dryRun) {
7533
+ if (dryRun) return;
7534
+ const content = JSON.stringify(payload, null, 2) + "\n";
7535
+ await writeFile9(path2, content, "utf-8");
7536
+ }
7537
+ async function appendJsonLines(path2, items, dryRun) {
7538
+ if (dryRun || items.length === 0) return;
7539
+ const lines = items.map((item) => JSON.stringify(item)).join("\n") + "\n";
7540
+ await writeFile9(path2, lines, { encoding: "utf-8", flag: "a" });
7541
+ }
7542
+ async function archiveLegacyFile(source, destDir, dryRun) {
7543
+ const fileName = source.split("/").pop() ?? source.replace(/[^a-zA-Z0-9._-]/g, "_");
7544
+ const target = join17(destDir, fileName);
7545
+ if (dryRun) return target;
7546
+ if (!existsSync17(destDir)) {
7547
+ mkdirSync4(destDir, { recursive: true });
7548
+ }
7549
+ const content = await readFile11(source, "utf-8");
7550
+ await writeFile9(target, content, "utf-8");
7551
+ return target;
7552
+ }
7553
+ async function migrateLegacyGovernance(options = {}) {
7554
+ const cwd = options.cwd ?? process.cwd();
7555
+ const now = options.now ?? /* @__PURE__ */ new Date();
7556
+ const nowIso = now.toISOString();
7557
+ const result = {
7558
+ migratedArchitecture: false,
7559
+ migratedTasks: false,
7560
+ archivedLegacyFiles: [],
7561
+ warnings: []
7562
+ };
7563
+ const store = new GovernanceStore(cwd);
7564
+ store.ensureStructure();
7565
+ const archPath = join17(cwd, LEGACY_ARCH_PATH);
7566
+ const activeArchPath = join17(cwd, ACTIVE_ARCH_PATH2);
7567
+ if (existsSync17(archPath) && !existsSync17(activeArchPath)) {
7568
+ const raw = await readFile11(archPath, "utf-8");
7569
+ const parsed = matter2(raw);
7570
+ const content = parsed.content.trim();
7571
+ if (!content) {
7572
+ result.warnings.push("Legacy ARCHITECTURE.md was empty; skipping architecture migration.");
7573
+ } else if (!options.dryRun) {
7574
+ const update = await store.updateArchitecture(
7575
+ content,
7576
+ "Migrated from legacy ARCHITECTURE.md",
7577
+ options.updatedBy ?? "archon migration"
7578
+ );
7579
+ if (!update.ok) {
7580
+ result.warnings.push(`Failed to migrate architecture: ${update.error}`);
7581
+ } else {
7582
+ result.migratedArchitecture = true;
7583
+ }
7584
+ } else {
7585
+ result.migratedArchitecture = true;
7586
+ }
7587
+ if (options.removeLegacy) {
7588
+ const archived = await archiveLegacyFile(archPath, join17(cwd, HISTORY_LEGACY_DIR), !!options.dryRun);
7589
+ result.archivedLegacyFiles.push(archived);
7590
+ if (!options.dryRun) {
7591
+ await unlink3(archPath);
7592
+ }
7593
+ }
7594
+ }
7595
+ const legacyTasksPath = join17(cwd, LEGACY_TASKS_PATH);
7596
+ const activeTasksPath = join17(cwd, ACTIVE_TASKS_PATH);
7597
+ if (existsSync17(legacyTasksPath) && !existsSync17(activeTasksPath)) {
7598
+ const rawTasks = await readFile11(legacyTasksPath, "utf-8");
7599
+ const parsedTasks = parseLegacyTasks(rawTasks);
7600
+ const { active, completed } = buildTaskEntries(parsedTasks, nowIso);
7601
+ if (active.length === 0 && completed.length === 0) {
7602
+ result.warnings.push("Legacy current-tasks.md did not contain actionable items.");
7603
+ } else {
7604
+ await writeJson(activeTasksPath, active, !!options.dryRun);
7605
+ await appendJsonLines(join17(cwd, ARCHIVE_COMPLETED_PATH), completed, !!options.dryRun);
7606
+ result.migratedTasks = true;
7607
+ }
7608
+ if (options.removeLegacy) {
7609
+ const archived = await archiveLegacyFile(legacyTasksPath, join17(cwd, HISTORY_LEGACY_DIR), !!options.dryRun);
7610
+ result.archivedLegacyFiles.push(archived);
7611
+ if (!options.dryRun) {
7612
+ await unlink3(legacyTasksPath);
7613
+ }
7614
+ }
7615
+ }
7616
+ if (existsSync17(join17(cwd, ACTIVE_ARCH_PATH2)) && existsSync17(join17(cwd, LEGACY_ARCH_PATH))) {
7617
+ result.warnings.push("Active architecture already exists; legacy ARCHITECTURE.md left untouched.");
7618
+ }
7619
+ if (existsSync17(join17(cwd, ACTIVE_TASKS_PATH)) && existsSync17(join17(cwd, LEGACY_TASKS_PATH))) {
7620
+ result.warnings.push("Active tasks already exist; legacy current-tasks.md left untouched.");
7621
+ }
7622
+ return result;
7623
+ }
7624
+
7625
+ // src/core/governance/sqlite.ts
7626
+ import { join as join18 } from "path";
7627
+ import matter3 from "gray-matter";
7628
+ import Database2 from "better-sqlite3";
7629
+ var ARCH_PATH = join18(".archon", "active", "architecture.md");
7630
+ var TASKS_PATH = join18(".archon", "active", "tasks.json");
7631
+ var HANDOFFS_PATH = join18(".archon", "history", "handoffs.jsonl");
7632
+ var DECISIONS_PATH = join18(".archon", "history", "decision_log.jsonl");
7633
+ var COMPLETED_PATH = join18(".archon", "archive", "completed_tasks.jsonl");
7634
+
7635
+ // src/cli/governance.ts
7636
+ var ACTIVE_ARCH_PATH3 = join19(".archon", "active", "architecture.md");
7637
+ var ACTIVE_TASKS_PATH2 = join19(".archon", "active", "tasks.json");
7638
+ var CURRENT_CONTEXT_PATH = join19(".archon", "current_context.md");
7639
+ var HANDOFF_HISTORY_PATH = join19(".archon", "history", "handoffs.jsonl");
7640
+ var COMPLETED_TASKS_PATH = join19(".archon", "archive", "completed_tasks.jsonl");
7641
+ var TASK_STATUSES = ["pending", "in_progress", "verification", "done"];
7642
+ function isTaskStatus(value) {
7643
+ return typeof value === "string" && TASK_STATUSES.includes(value);
7644
+ }
7645
+ function resolveArchitecturePath2(cwd) {
7646
+ const agdPath = join19(cwd, ACTIVE_ARCH_PATH3);
7647
+ if (existsSync18(agdPath)) {
7648
+ return { path: agdPath, source: "agd" };
7649
+ }
7650
+ const legacyPath = join19(cwd, "ARCHITECTURE.md");
7651
+ if (existsSync18(legacyPath)) {
7652
+ return { path: legacyPath, source: "legacy" };
7653
+ }
7654
+ return { path: null, source: null };
7655
+ }
7656
+ function parseTasks(raw) {
7657
+ if (!Array.isArray(raw)) return null;
7658
+ const tasks = [];
7659
+ for (const item of raw) {
7660
+ if (typeof item !== "object" || item === null) return null;
7661
+ const entry = item;
7662
+ if (typeof entry["id"] !== "string") return null;
7663
+ if (typeof entry["description"] !== "string") return null;
7664
+ if (!isTaskStatus(entry["status"])) return null;
7665
+ if (typeof entry["created_at"] !== "string") return null;
7666
+ tasks.push({
7667
+ id: entry["id"],
7668
+ description: entry["description"],
7669
+ status: entry["status"],
7670
+ created_at: entry["created_at"],
7671
+ parent_id: typeof entry["parent_id"] === "string" ? entry["parent_id"] : void 0,
7672
+ assigned_to: typeof entry["assigned_to"] === "string" ? entry["assigned_to"] : void 0,
7673
+ updated_at: typeof entry["updated_at"] === "string" ? entry["updated_at"] : void 0,
7674
+ notes: typeof entry["notes"] === "string" ? entry["notes"] : void 0
7675
+ });
7676
+ }
7677
+ return tasks;
7678
+ }
7679
+ function countTaskStatuses(tasks) {
7680
+ const counts = {
7681
+ pending: 0,
7682
+ in_progress: 0,
7683
+ verification: 0,
7684
+ done: 0
7685
+ };
7686
+ for (const task of tasks) {
7687
+ if (counts[task.status] === void 0) continue;
7688
+ counts[task.status] += 1;
7689
+ }
7690
+ return counts;
7691
+ }
7692
+ function parseContextMeta(content) {
7693
+ const timestampMatch = content.match(/^Timestamp:\s*(.+)$/m);
7694
+ const reasonMatch = content.match(/^Reason:\s*(.+)$/m);
7695
+ return {
7696
+ timestamp: timestampMatch?.[1]?.trim(),
7697
+ reason: reasonMatch?.[1]?.trim()
7698
+ };
7699
+ }
7700
+ function renderStatusCounts(counts) {
7701
+ const total = Object.values(counts).reduce((sum, value) => sum + value, 0);
7702
+ if (total === 0) return;
7703
+ console.log(chalk17.dim(` Tasks: ${total} total`));
7704
+ console.log(
7705
+ chalk17.dim(
7706
+ ` pending: ${counts.pending} | in_progress: ${counts.in_progress} | verification: ${counts.verification} | done: ${counts.done}`
7707
+ )
7708
+ );
7709
+ }
7710
+ function lineCount(content) {
7711
+ const trimmed = content.trim();
7712
+ if (!trimmed) return 0;
7713
+ return trimmed.split("\n").length;
7714
+ }
7715
+ function createGovernanceCommand() {
7716
+ const governance = new Command2("governance").alias("gov").description("Manage governance store (AGD)");
7717
+ governance.command("status").description("Show governance status from AGD store").action(async () => {
7718
+ const cwd = process.cwd();
7719
+ const store = new GovernanceStore(cwd);
7720
+ store.ensureStructure();
7721
+ console.log(chalk17.bold("\nGovernance Status\n"));
7722
+ const archInfo = resolveArchitecturePath2(cwd);
7723
+ if (archInfo.path) {
7724
+ const parser = new ArchitectureParser(archInfo.path);
7725
+ const parsed = await parser.parse();
7726
+ if (parsed.success && parsed.schema) {
7727
+ const posture = parsed.schema.qualityLevel?.posture ?? "unknown";
7728
+ console.log(chalk17.green(" \u2713") + ` Architecture (${archInfo.source})`);
7729
+ console.log(chalk17.dim(` posture: ${posture}`));
7730
+ console.log(chalk17.dim(` invariants: ${parsed.schema.invariants.length}`));
7731
+ console.log(chalk17.dim(` protected paths: ${parsed.schema.protectedPaths.length}`));
7732
+ } else {
7733
+ console.log(chalk17.yellow(" ! Architecture present but failed to parse"));
7734
+ }
7735
+ } else {
7736
+ console.log(chalk17.yellow(" \u25CB No architecture file found"));
7737
+ }
7738
+ const tasksPath = join19(cwd, ACTIVE_TASKS_PATH2);
7739
+ if (existsSync18(tasksPath)) {
7740
+ try {
7741
+ const tasksRaw = JSON.parse(readFileSync6(tasksPath, "utf-8"));
7742
+ const tasks2 = parseTasks(tasksRaw);
7743
+ if (tasks2) {
7744
+ renderStatusCounts(countTaskStatuses(tasks2));
7745
+ } else {
7746
+ console.log(chalk17.yellow(" ! tasks.json present but invalid"));
7747
+ }
7748
+ } catch {
7749
+ console.log(chalk17.yellow(" ! tasks.json present but unreadable"));
7750
+ }
7751
+ }
7752
+ const contextPath = join19(cwd, CURRENT_CONTEXT_PATH);
7753
+ if (existsSync18(contextPath)) {
7754
+ const content = readFileSync6(contextPath, "utf-8");
7755
+ const meta = parseContextMeta(content);
7756
+ console.log(chalk17.dim(` Handoff: ${meta.timestamp ?? "present"}`));
7757
+ if (meta.reason) {
7758
+ console.log(chalk17.dim(` reason: ${meta.reason}`));
7759
+ }
7760
+ }
7761
+ const handoffHistoryPath = join19(cwd, HANDOFF_HISTORY_PATH);
7762
+ if (existsSync18(handoffHistoryPath)) {
7763
+ const count = lineCount(readFileSync6(handoffHistoryPath, "utf-8"));
7764
+ if (count > 0) {
7765
+ console.log(chalk17.dim(` Handoff entries: ${count}`));
7766
+ }
7767
+ }
7768
+ const completedPath = join19(cwd, COMPLETED_TASKS_PATH);
7769
+ if (existsSync18(completedPath)) {
7770
+ const count = lineCount(readFileSync6(completedPath, "utf-8"));
7771
+ if (count > 0) {
7772
+ console.log(chalk17.dim(` Completed tasks archived: ${count}`));
7773
+ }
7774
+ }
7775
+ console.log("");
7776
+ });
7777
+ const architecture = governance.command("architecture").description("Read or update governance architecture");
7778
+ architecture.command("show").description("Show active architecture content").option("--raw", "Show full file including frontmatter").action(async (options) => {
7779
+ const cwd = process.cwd();
7780
+ const store = new GovernanceStore(cwd);
7781
+ const archInfo = resolveArchitecturePath2(cwd);
7782
+ if (!archInfo.path) {
7783
+ console.log(chalk17.yellow("No architecture file found."));
7784
+ return;
7785
+ }
7786
+ if (options.raw) {
7787
+ const raw = readFileSync6(archInfo.path, "utf-8");
7788
+ console.log(raw.trimEnd());
7789
+ return;
7790
+ }
7791
+ if (archInfo.source === "agd") {
7792
+ const result = await store.readArchitecture();
7793
+ if (!result.ok) {
7794
+ console.log(chalk17.red(`Failed to read architecture: ${result.error}`));
7795
+ return;
7796
+ }
7797
+ if (!result.value) {
7798
+ console.log(chalk17.yellow("Architecture file is empty."));
7799
+ return;
7800
+ }
7801
+ console.log(result.value);
7802
+ return;
7803
+ }
7804
+ const legacyRaw = readFileSync6(archInfo.path, "utf-8");
7805
+ const legacyParsed = matter4(legacyRaw);
7806
+ const legacyContent = legacyParsed.content.trim();
7807
+ if (!legacyContent) {
7808
+ console.log(chalk17.yellow("Architecture file is empty."));
7809
+ return;
7810
+ }
7811
+ console.log(legacyContent);
7812
+ });
7813
+ architecture.command("update").description("Update active architecture with change reason").requiredOption("-f, --file <path>", "Path to new architecture content").requiredOption("-r, --reason <text>", "Reason for the change (required)").option("-b, --by <name>", "Updated by (optional)").action(async (options) => {
7814
+ const cwd = process.cwd();
7815
+ const filePath = options.file;
7816
+ if (!existsSync18(filePath)) {
7817
+ console.log(chalk17.red(`File not found: ${filePath}`));
7818
+ process.exit(1);
7819
+ }
7820
+ const content = await readFile12(filePath, "utf-8");
7821
+ const store = new GovernanceStore(cwd);
7822
+ const result = await store.updateArchitecture(content, options.reason, options.by);
7823
+ if (!result.ok) {
7824
+ console.log(chalk17.red(`Failed to update architecture: ${result.error}`));
7825
+ process.exit(1);
7826
+ }
7827
+ console.log(chalk17.green("\u2713 Architecture updated"));
7828
+ });
7829
+ const tasks = governance.command("task").description("Update tasks in governance store");
7830
+ tasks.command("update <taskId>").description("Update task status and notes").requiredOption("-s, --status <status>", "Status: pending, in_progress, verification, done").option("-n, --notes <text>", "Optional notes").action(async (taskId, options) => {
7831
+ const status2 = options.status;
7832
+ if (!isTaskStatus(status2)) {
7833
+ console.log(chalk17.red(`Invalid status: ${options.status}`));
7834
+ process.exit(1);
7835
+ }
7836
+ const store = new GovernanceStore(process.cwd());
7837
+ const result = await store.updateTask(taskId, status2, options.notes);
7838
+ if (!result.ok) {
7839
+ console.log(chalk17.red(`Failed to update task: ${result.error}`));
7840
+ process.exit(1);
7841
+ }
7842
+ console.log(chalk17.green(`\u2713 Task ${taskId} updated to ${status2}`));
7843
+ });
7844
+ governance.command("handoff").description("Log a handoff entry and update current context").requiredOption("-r, --reason <text>", "Reason for handoff").requiredOption("-s, --summary <text>", "Summary (single paragraph)").requiredOption("-n, --next <actions...>", "Next actions (space-separated)").option("-f, --from <agent>", "Agent or source name").option("-t, --timestamp <iso>", "Timestamp override (ISO 8601)").action(async (options) => {
7845
+ const store = new GovernanceStore(process.cwd());
7846
+ const entry = {
7847
+ timestamp: options.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
7848
+ from_agent: options.from,
7849
+ reason: options.reason,
7850
+ summary: options.summary,
7851
+ next_actions: options.next
7852
+ };
7853
+ const result = await store.logHandoff(entry);
7854
+ if (!result.ok) {
7855
+ console.log(chalk17.red(`Failed to log handoff: ${result.error}`));
7856
+ process.exit(1);
7857
+ }
7858
+ console.log(chalk17.green("\u2713 Handoff logged"));
7859
+ });
7860
+ governance.command("migrate").description("Migrate legacy governance files into AGD structure").option("--remove-legacy", "Archive legacy files after migration").option("--dry-run", "Show what would change without writing files").option("-b, --by <name>", "Updated by label for architecture migration").action(async (options) => {
7861
+ const result = await migrateLegacyGovernance({
7862
+ cwd: process.cwd(),
7863
+ removeLegacy: options.removeLegacy,
7864
+ dryRun: options.dryRun,
7865
+ updatedBy: options.by
7866
+ });
7867
+ console.log(chalk17.bold("\nMigration Summary"));
7868
+ console.log(
7869
+ result.migratedArchitecture ? chalk17.green(" \u2713 Architecture migrated") : chalk17.dim(" \u25CB Architecture migration skipped")
7870
+ );
7871
+ console.log(
7872
+ result.migratedTasks ? chalk17.green(" \u2713 Tasks migrated") : chalk17.dim(" \u25CB Tasks migration skipped")
7873
+ );
7874
+ if (result.archivedLegacyFiles.length > 0) {
7875
+ console.log(chalk17.dim(" Archived legacy files:"));
7876
+ for (const file of result.archivedLegacyFiles) {
7877
+ console.log(chalk17.dim(` - ${file}`));
7878
+ }
7879
+ }
7880
+ if (result.warnings.length > 0) {
7881
+ console.log(chalk17.yellow("\nWarnings:"));
7882
+ for (const warning of result.warnings) {
7883
+ console.log(chalk17.yellow(` - ${warning}`));
7884
+ }
7885
+ }
7886
+ console.log("");
7887
+ });
7888
+ return governance;
7889
+ }
7890
+
7038
7891
  // src/cli/index.ts
7039
- var program = new Command2();
7892
+ var program = new Command3();
7040
7893
  program.name("archon").description("Local-first AI-powered development governance").version(getCurrentVersion()).action(async () => {
7041
7894
  const cwd = process.cwd();
7042
7895
  const wasInitialized = isInitialized(cwd);
7043
7896
  if (!wasInitialized) {
7044
- console.log(chalk17.blue("\nArchonDev is not initialized in this folder.\n"));
7897
+ console.log(chalk18.blue("\nArchonDev is not initialized in this folder.\n"));
7045
7898
  await init({ analyze: true, git: true });
7046
7899
  }
7047
7900
  await start({ skipGovernanceBanner: !wasInitialized });
@@ -7049,7 +7902,7 @@ program.name("archon").description("Local-first AI-powered development governanc
7049
7902
  program.command("login").description("Authenticate with ArchonDev").option("-p, --provider <provider>", "OAuth provider (github or google)", "github").action(async (options) => {
7050
7903
  const provider = options.provider;
7051
7904
  if (provider !== "github" && provider !== "google") {
7052
- console.error(chalk17.red('Invalid provider. Use "github" or "google"'));
7905
+ console.error(chalk18.red('Invalid provider. Use "github" or "google"'));
7053
7906
  process.exit(1);
7054
7907
  }
7055
7908
  await login(provider);
@@ -7183,6 +8036,7 @@ reviewCommand.action(async () => {
7183
8036
  await reviewStatus();
7184
8037
  });
7185
8038
  program.addCommand(createDepsCommand());
8039
+ program.addCommand(createGovernanceCommand());
7186
8040
  var a11yCommand = program.command("a11y").description("Accessibility checking and compliance for web deployments");
7187
8041
  a11yCommand.command("check").description("Run WCAG 2.2 AA accessibility audit").option("-v, --verbose", "Show all issues including minor ones").option("-f, --format <format>", "Output format (text or json)", "text").action(async (options) => {
7188
8042
  await a11yCheck(options);
@@ -7243,7 +8097,7 @@ cleanupCmd.command("check").description("Analyze workspace for bloat and mainten
7243
8097
  cleanupCmd.command("run").description("Execute cleanup (archive old entries, remove stale files)").action(cleanupRun);
7244
8098
  cleanupCmd.command("auto").description("Enable/disable automatic cleanup checks").argument("[action]", "enable, disable, or status", "status").action(async (action) => {
7245
8099
  if (action !== "enable" && action !== "disable" && action !== "status") {
7246
- console.error(chalk17.red("Invalid action. Use: enable, disable, or status"));
8100
+ console.error(chalk18.red("Invalid action. Use: enable, disable, or status"));
7247
8101
  process.exit(1);
7248
8102
  }
7249
8103
  await cleanupAuto(action);