archondev 2.19.0 → 2.19.2

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
@@ -32,7 +32,7 @@ Copy governance files into any project. Works with your existing AI tools: **Cur
32
32
  [Download Lite Packages →](https://archondev.io/download)
33
33
 
34
34
  **What you get:**
35
- - ARCHITECTURE.md template with best practices
35
+ - .archon/active/architecture.md template with best practices
36
36
  - **Quality Level / Posture** — Tell AI if it's prototype, production, or enterprise-grade
37
37
  - IDE-specific rule files (.cursorrules, CLAUDE.md, GEMINI.md, etc.)
38
38
  - Progress tracking templates
@@ -45,6 +45,15 @@ Copy governance files into any project. Works with your existing AI tools: **Cur
45
45
  - **Pre-Deploy Accessibility** — WCAG 2.2 AA check before going live, legal liability warnings
46
46
  - Works with any AI coding assistant
47
47
 
48
+ ### Local Governance SQLite (Dev Only)
49
+
50
+ Governance data for this repo lives in `.archon/governance.db` and is local-only. It is never synced to Supabase.
51
+ To initialize or refresh it:
52
+
53
+ ```bash
54
+ pnpm exec tsx scripts/init-governance-db.ts
55
+ ```
56
+
48
57
  ---
49
58
 
50
59
  ## Commands
@@ -84,14 +93,16 @@ Copy governance files into any project. Works with your existing AI tools: **Cur
84
93
  | `archon seo fix` | Apply recommended SEO fixes |
85
94
  | `archon geo identity` | Generate brand identity phrases for AI citation |
86
95
  | `archon geo schema` | Generate JSON-LD schemas |
96
+ | `archon governance status` | Show governance status (AGD) |
97
+ | `archon governance architecture update` | Update architecture with change reason |
98
+ | `archon governance task update` | Update governance tasks |
99
+ | `archon governance handoff` | Log handoff + current context |
100
+ | `archon governance migrate` | Migrate legacy governance files |
101
+ | `archon governance sqlite-init` | Initialize or refresh local governance SQLite DB |
87
102
  | `archon github connect` | Link GitHub account for cloud execution |
88
103
  | `archon github status` | Check GitHub connection status |
89
104
  | `archon session save [name]` | Save current session to cloud |
90
105
  | `archon session resume [id]` | Resume session on another device |
91
-
92
- **Notes:**
93
- - Credits tier shows your balance and per‑model usage on startup; use `archon credits` for full details and history.
94
- - You can paste multi‑line requests into interactive prompts; Archon captures them as a single response.
95
106
  | `archon execute ATOM --cloud` | Execute in cloud (creates PR when done) |
96
107
  | `archon cloud status` | List cloud executions |
97
108
  | `archon parallel cloud ATOM-001 ATOM-002` | Queue multiple atoms for cloud execution (Credits tier) |
@@ -104,6 +115,10 @@ Copy governance files into any project. Works with your existing AI tools: **Cur
104
115
  | `archon cleanup run` | Execute cleanup tasks |
105
116
  | `archon cleanup auto [enable\|disable]` | Enable/disable auto cleanup on start |
106
117
 
118
+ **Notes:**
119
+ - Credits tier shows your balance and per‑model usage on startup; use `archon credits` for full details and history.
120
+ - You can paste multi‑line requests into interactive prompts; Archon captures them as a single response.
121
+
107
122
  **Tip:** Use `archon plan --edit` to adjust title and acceptance criteria before planning.
108
123
  **Web Checks:** If Archon detects a web project, it prompts to run A11y/SEO/GEO checks and stores your preference in `.archon/config.yaml`.
109
124
 
@@ -118,6 +133,13 @@ Copy governance files into any project. Works with your existing AI tools: **Cur
118
133
 
119
134
  No subscriptions. No commitments. Start free, upgrade anytime with `archon upgrade`.
120
135
 
136
+ ### BYOK Key Security
137
+
138
+ - Your API keys are stored locally in `~/.archon/keys.json` (never uploaded to ArchonDev servers).
139
+ - Keys are encrypted at rest with AES-256-GCM and the file is set to owner-only permissions (`0600`).
140
+ - BYOK runs locally; cloud execution is Credits-only.
141
+ - If your device is compromised, an attacker could access local files. Treat keys as sensitive secrets.
142
+
121
143
  ### Claude Pro/Max Subscription Support (Coming Soon)
122
144
 
123
145
  If you have an existing Claude subscription, you'll soon be able to use it with ArchonDev instead of API keys:
@@ -2,9 +2,9 @@ import {
2
2
  login,
3
3
  logout,
4
4
  status
5
- } from "./chunk-CZCY63EY.js";
5
+ } from "./chunk-F4OUCZPN.js";
6
6
  import "./chunk-M4LGRTLC.js";
7
- import "./chunk-LBBHM4I5.js";
7
+ import "./chunk-GBYW3YAY.js";
8
8
  import "./chunk-SVU7MLG6.js";
9
9
  import "./chunk-4VNS5WPM.js";
10
10
  export {
@@ -14,7 +14,7 @@ import {
14
14
  } from "./chunk-RDG5BUED.js";
15
15
  import {
16
16
  login
17
- } from "./chunk-CZCY63EY.js";
17
+ } from "./chunk-F4OUCZPN.js";
18
18
  import {
19
19
  getApiUrl,
20
20
  getAuthToken,
@@ -1071,7 +1071,7 @@ async function manageApiKeys() {
1071
1071
  if (removeIndex >= 0 && removeIndex < providers.length) {
1072
1072
  const providerToRemove = providers[removeIndex];
1073
1073
  if (providerToRemove) {
1074
- const { removeKey } = await import("./keys-U4QZE5YB.js");
1074
+ const { removeKey } = await import("./keys-T2VPHE7Z.js");
1075
1075
  await removeKey(providerToRemove);
1076
1076
  }
1077
1077
  }
@@ -1079,7 +1079,7 @@ async function manageApiKeys() {
1079
1079
  }
1080
1080
  const provider = providerMap[choice];
1081
1081
  if (provider) {
1082
- const { addKey } = await import("./keys-U4QZE5YB.js");
1082
+ const { addKey } = await import("./keys-T2VPHE7Z.js");
1083
1083
  await addKey(provider);
1084
1084
  }
1085
1085
  }
@@ -6,7 +6,7 @@ import {
6
6
  handleTierSetup,
7
7
  promptTierSelection,
8
8
  updateUserTier
9
- } from "./chunk-LBBHM4I5.js";
9
+ } from "./chunk-GBYW3YAY.js";
10
10
  import {
11
11
  clearConfig,
12
12
  loadConfig,
@@ -43,7 +43,7 @@ async function offerReauthentication(reason) {
43
43
  return false;
44
44
  }
45
45
  console.log();
46
- const { login } = await import("./auth-HQBAG4CR.js");
46
+ const { login } = await import("./auth-7DNVC6UX.js");
47
47
  await login({ skipTierSelection: true });
48
48
  const { loadConfig: reload } = await import("./config-JBPM2YAB.js");
49
49
  const config = await reload();
@@ -207,7 +207,7 @@ async function promptForApiKey() {
207
207
  return;
208
208
  }
209
209
  if (provider) {
210
- const { addKey } = await import("./keys-U4QZE5YB.js");
210
+ const { addKey } = await import("./keys-T2VPHE7Z.js");
211
211
  await addKey(provider, {});
212
212
  console.log();
213
213
  const addAnother = await promptYesNo("Would you like to add another API key?", false);
@@ -455,7 +455,7 @@ function promptYesNo(question, defaultValue) {
455
455
  }
456
456
  async function showKeyManagementMenu() {
457
457
  const { keyManager } = await import("./keys-THCHXIFD.js");
458
- const { listKeys, addKey, removeKey } = await import("./keys-U4QZE5YB.js");
458
+ const { listKeys, addKey, removeKey } = await import("./keys-T2VPHE7Z.js");
459
459
  console.log();
460
460
  console.log(chalk.bold("API Key Management"));
461
461
  console.log(chalk.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"));
@@ -47,6 +47,10 @@ async function addKey(provider, options = {}) {
47
47
  process.exit(1);
48
48
  }
49
49
  const label = options.label ?? "default";
50
+ console.log(chalk.dim("Security: Your API key stays on this machine (never uploaded)."));
51
+ console.log(chalk.dim(" \u2022 Encrypted at rest (AES-256-GCM)"));
52
+ console.log(chalk.dim(" \u2022 Stored in ~/.archon/keys.json with owner-only permissions (0600)"));
53
+ console.log(chalk.dim(" \u2022 Used only for local BYOK calls"));
50
54
  const apiKey = await promptForKey(provider);
51
55
  if (!apiKey) {
52
56
  console.error(chalk.red("API key cannot be empty"));
package/dist/index.js CHANGED
@@ -27,7 +27,7 @@ import {
27
27
  setPreference,
28
28
  showExecutionPreferences,
29
29
  showPreferences
30
- } from "./chunk-ZJXIOETW.js";
30
+ } from "./chunk-CTWVQ6F3.js";
31
31
  import {
32
32
  a11yBadge,
33
33
  a11yCheck,
@@ -85,14 +85,14 @@ import {
85
85
  listKeys,
86
86
  removeKey,
87
87
  setPrimaryKey
88
- } from "./chunk-75J2JMU3.js";
88
+ } from "./chunk-JNFXMWBR.js";
89
89
  import "./chunk-TFSHS7EN.js";
90
90
  import "./chunk-RDG5BUED.js";
91
91
  import {
92
92
  login,
93
93
  logout,
94
94
  status
95
- } from "./chunk-CZCY63EY.js";
95
+ } from "./chunk-F4OUCZPN.js";
96
96
  import {
97
97
  API_URL,
98
98
  SUPABASE_ANON_KEY,
@@ -102,7 +102,7 @@ import {
102
102
  handleTierSetup,
103
103
  promptTierSelection,
104
104
  updateUserTier
105
- } from "./chunk-LBBHM4I5.js";
105
+ } from "./chunk-GBYW3YAY.js";
106
106
  import {
107
107
  getAuthToken,
108
108
  loadConfig,
@@ -2850,22 +2850,22 @@ async function start(options = {}) {
2850
2850
  const choice = await promptWithCommands("What would you like to do?", { allowMultiline: true });
2851
2851
  switch (choice) {
2852
2852
  case "1":
2853
- const { handleTierSetup: handleTierSetup2 } = await import("./tier-selection-426HA765.js");
2853
+ const { handleTierSetup: handleTierSetup2 } = await import("./tier-selection-XFBM4SZ4.js");
2854
2854
  await handleTierSetup2("BYOK");
2855
2855
  break;
2856
2856
  case "2":
2857
- const { updateUserTier: updateUserTier2 } = await import("./tier-selection-426HA765.js");
2857
+ const { updateUserTier: updateUserTier2 } = await import("./tier-selection-XFBM4SZ4.js");
2858
2858
  const result = await updateUserTier2("CREDITS");
2859
2859
  if (result.success) {
2860
2860
  config.tier = "CREDITS";
2861
2861
  await saveConfig(config);
2862
2862
  console.log(chalk6.green("\u2713 Switched to Managed Plan"));
2863
- const { handleTierSetup: setupCredits } = await import("./tier-selection-426HA765.js");
2863
+ const { handleTierSetup: setupCredits } = await import("./tier-selection-XFBM4SZ4.js");
2864
2864
  await setupCredits("CREDITS");
2865
2865
  }
2866
2866
  break;
2867
2867
  case "3":
2868
- const { updateUserTier: downgrade } = await import("./tier-selection-426HA765.js");
2868
+ const { updateUserTier: downgrade } = await import("./tier-selection-XFBM4SZ4.js");
2869
2869
  const downgradeResult = await downgrade("FREE");
2870
2870
  if (downgradeResult.success) {
2871
2871
  config.tier = "FREE";
@@ -3236,7 +3236,7 @@ async function showNewProjectMenu(cwd) {
3236
3236
  await quickStart(cwd);
3237
3237
  break;
3238
3238
  case "3": {
3239
- const description = await prompt("Describe what you want to do");
3239
+ const description = await promptWithCommands("Describe what you want to do", { allowMultiline: true });
3240
3240
  if (description.trim()) {
3241
3241
  const { plan: plan2 } = await import("./plan-HCYXLSSD.js");
3242
3242
  await plan2(description, {});
@@ -3302,7 +3302,7 @@ async function runExploreFlow(cwd) {
3302
3302
  const choice = await promptWithCommands("Enter choice");
3303
3303
  switch (choice.toLowerCase()) {
3304
3304
  case "1": {
3305
- const description = await prompt("Describe what you want to do");
3305
+ const description = await promptWithCommands("Describe what you want to do", { allowMultiline: true });
3306
3306
  if (description.trim()) {
3307
3307
  const { plan: plan2 } = await import("./plan-HCYXLSSD.js");
3308
3308
  await plan2(description, {});
@@ -3564,7 +3564,7 @@ ${state.forbiddenPatterns?.length ? `- **Forbidden patterns:** ${state.forbidden
3564
3564
  console.log();
3565
3565
  const continueChoice = await promptYesNo("Would you like to plan your first task now?", true);
3566
3566
  if (continueChoice) {
3567
- const description = await prompt("Describe what you want to build first");
3567
+ const description = await promptWithCommands("Describe what you want to build first", { allowMultiline: true });
3568
3568
  if (description.trim()) {
3569
3569
  const { plan: plan2 } = await import("./plan-HCYXLSSD.js");
3570
3570
  await plan2(description, {});
@@ -3649,7 +3649,7 @@ async function showAdaptExistingMenu(cwd, state) {
3649
3649
  await runExploreFlow(cwd);
3650
3650
  break;
3651
3651
  case "2": {
3652
- const description = await prompt("Describe what you want to do");
3652
+ const description = await promptWithCommands("Describe what you want to do", { allowMultiline: true });
3653
3653
  if (description.trim()) {
3654
3654
  const { plan: plan2 } = await import("./plan-HCYXLSSD.js");
3655
3655
  await plan2(description, {});
@@ -3788,7 +3788,7 @@ async function showMainMenu() {
3788
3788
  } }] : [],
3789
3789
  { key: "7", label: "Settings & Preferences", action: () => settingsMenu() },
3790
3790
  { key: "8", label: "Upgrade tier", action: async () => {
3791
- const { showUpgradeMenu } = await import("./tier-selection-426HA765.js");
3791
+ const { showUpgradeMenu } = await import("./tier-selection-XFBM4SZ4.js");
3792
3792
  await showUpgradeMenu();
3793
3793
  await showMainMenu();
3794
3794
  } },
@@ -3828,7 +3828,7 @@ async function showReviewProgress(cwd) {
3828
3828
  }
3829
3829
  async function planTask() {
3830
3830
  const { plan: plan2 } = await import("./plan-HCYXLSSD.js");
3831
- const description = await prompt("Describe what you want to build");
3831
+ const description = await promptWithCommands("Describe what you want to build", { allowMultiline: true });
3832
3832
  if (description.trim()) {
3833
3833
  await plan2(description, {});
3834
3834
  }
@@ -3840,7 +3840,7 @@ async function listAtoms() {
3840
3840
  async function executeNext() {
3841
3841
  const { listLocalAtoms: listLocalAtoms2 } = await import("./plan-HCYXLSSD.js");
3842
3842
  const { analyzeProject, getComplexityDescription, getModeDescription } = await import("./orchestration-HIF3KP25.js");
3843
- const { loadExecutionPreferences } = await import("./preferences-I6WETXOI.js");
3843
+ const { loadExecutionPreferences } = await import("./preferences-OAOZCZGR.js");
3844
3844
  const cwd = process.cwd();
3845
3845
  const atoms = await listLocalAtoms2();
3846
3846
  const pendingAtoms = atoms.filter((a) => a.status === "READY" || a.status === "IN_PROGRESS");
@@ -3935,11 +3935,11 @@ async function reportBug() {
3935
3935
  }
3936
3936
  }
3937
3937
  async function viewStatus() {
3938
- const { status: status2 } = await import("./auth-HQBAG4CR.js");
3938
+ const { status: status2 } = await import("./auth-7DNVC6UX.js");
3939
3939
  await status2();
3940
3940
  }
3941
3941
  async function settingsMenu() {
3942
- const { interactiveSettings } = await import("./preferences-I6WETXOI.js");
3942
+ const { interactiveSettings } = await import("./preferences-OAOZCZGR.js");
3943
3943
  await interactiveSettings();
3944
3944
  await showMainMenu();
3945
3945
  }
@@ -3998,12 +3998,12 @@ async function reviewCode() {
3998
3998
  async function handleInSessionCommand(input) {
3999
3999
  const normalized = input.toLowerCase().trim();
4000
4000
  if (normalized === "upgrade" || normalized === "archon upgrade" || normalized === "pricing" || normalized === "archon pricing") {
4001
- const { showUpgradeMenu } = await import("./tier-selection-426HA765.js");
4001
+ const { showUpgradeMenu } = await import("./tier-selection-XFBM4SZ4.js");
4002
4002
  await showUpgradeMenu();
4003
4003
  return true;
4004
4004
  }
4005
4005
  if (normalized === "status" || normalized === "archon status") {
4006
- const { status: status2 } = await import("./auth-HQBAG4CR.js");
4006
+ const { status: status2 } = await import("./auth-7DNVC6UX.js");
4007
4007
  await status2();
4008
4008
  return true;
4009
4009
  }
@@ -4019,7 +4019,7 @@ async function handleInSessionCommand(input) {
4019
4019
  return true;
4020
4020
  }
4021
4021
  if (normalized === "keys" || normalized === "archon keys") {
4022
- const { listKeys: listKeys2 } = await import("./keys-U4QZE5YB.js");
4022
+ const { listKeys: listKeys2 } = await import("./keys-T2VPHE7Z.js");
4023
4023
  await listKeys2();
4024
4024
  return true;
4025
4025
  }
@@ -4041,32 +4041,28 @@ function prompt(question) {
4041
4041
  });
4042
4042
  });
4043
4043
  }
4044
- function promptMultiline(question, idleMs = 250) {
4044
+ function promptMultiline(question) {
4045
4045
  return new Promise((resolve) => {
4046
4046
  const rl = readline.createInterface({
4047
4047
  input: process.stdin,
4048
4048
  output: process.stdout
4049
4049
  });
4050
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
4051
  rl.on("line", (line) => {
4052
+ if (line.trim() === ".") {
4053
+ rl.close();
4054
+ return;
4055
+ }
4062
4056
  lines.push(line);
4063
- scheduleFinish();
4064
4057
  });
4065
4058
  rl.on("SIGINT", () => {
4066
4059
  rl.close();
4067
4060
  process.exit(0);
4068
4061
  });
4069
- rl.setPrompt(`${chalk6.cyan("?")} ${question}: `);
4062
+ rl.on("close", () => {
4063
+ resolve(lines.join("\n").trimEnd());
4064
+ });
4065
+ rl.setPrompt(`${chalk6.cyan("?")} ${question} (multi-line: end with a single '.' line or Ctrl+D): `);
4070
4066
  rl.prompt();
4071
4067
  });
4072
4068
  }
@@ -7138,7 +7134,7 @@ async function modelsList() {
7138
7134
  // src/cli/governance.ts
7139
7135
  import { Command as Command2 } from "commander";
7140
7136
  import chalk17 from "chalk";
7141
- import { existsSync as existsSync18, readFileSync as readFileSync6 } from "fs";
7137
+ import { existsSync as existsSync19, readFileSync as readFileSync7 } from "fs";
7142
7138
  import { readFile as readFile12 } from "fs/promises";
7143
7139
  import { join as join19 } from "path";
7144
7140
  import matter4 from "gray-matter";
@@ -7623,6 +7619,7 @@ async function migrateLegacyGovernance(options = {}) {
7623
7619
  }
7624
7620
 
7625
7621
  // src/core/governance/sqlite.ts
7622
+ import { existsSync as existsSync18, mkdirSync as mkdirSync5, readFileSync as readFileSync6 } from "fs";
7626
7623
  import { join as join18 } from "path";
7627
7624
  import matter3 from "gray-matter";
7628
7625
  import Database2 from "better-sqlite3";
@@ -7631,6 +7628,262 @@ var TASKS_PATH = join18(".archon", "active", "tasks.json");
7631
7628
  var HANDOFFS_PATH = join18(".archon", "history", "handoffs.jsonl");
7632
7629
  var DECISIONS_PATH = join18(".archon", "history", "decision_log.jsonl");
7633
7630
  var COMPLETED_PATH = join18(".archon", "archive", "completed_tasks.jsonl");
7631
+ var GovernanceSqliteView = class {
7632
+ db = null;
7633
+ config;
7634
+ constructor(config = {}) {
7635
+ this.config = config;
7636
+ }
7637
+ init(cwd) {
7638
+ const archonDir = join18(cwd, ".archon");
7639
+ if (!existsSync18(archonDir)) {
7640
+ mkdirSync5(archonDir, { recursive: true });
7641
+ }
7642
+ const dbPath = this.config.inMemory ? ":memory:" : join18(cwd, this.config.dbPath ?? ".archon/governance.db");
7643
+ this.db = new Database2(dbPath);
7644
+ this.db.exec(`
7645
+ PRAGMA journal_mode = WAL;
7646
+ CREATE TABLE IF NOT EXISTS architecture (
7647
+ id TEXT PRIMARY KEY,
7648
+ version REAL,
7649
+ last_updated TEXT,
7650
+ updated_by TEXT,
7651
+ change_reason TEXT,
7652
+ content TEXT
7653
+ );
7654
+ CREATE TABLE IF NOT EXISTS tasks (
7655
+ id TEXT PRIMARY KEY,
7656
+ description TEXT NOT NULL,
7657
+ status TEXT NOT NULL,
7658
+ created_at TEXT NOT NULL,
7659
+ updated_at TEXT,
7660
+ notes TEXT
7661
+ );
7662
+ CREATE TABLE IF NOT EXISTS completed_tasks (
7663
+ id TEXT PRIMARY KEY,
7664
+ description TEXT NOT NULL,
7665
+ status TEXT NOT NULL,
7666
+ created_at TEXT NOT NULL,
7667
+ updated_at TEXT,
7668
+ notes TEXT
7669
+ );
7670
+ CREATE TABLE IF NOT EXISTS handoffs (
7671
+ id TEXT PRIMARY KEY,
7672
+ timestamp TEXT NOT NULL,
7673
+ from_agent TEXT,
7674
+ reason TEXT NOT NULL,
7675
+ summary TEXT NOT NULL,
7676
+ next_actions TEXT NOT NULL
7677
+ );
7678
+ CREATE TABLE IF NOT EXISTS decisions (
7679
+ id TEXT PRIMARY KEY,
7680
+ timestamp TEXT NOT NULL,
7681
+ category TEXT NOT NULL,
7682
+ change_reason TEXT NOT NULL,
7683
+ updated_by TEXT,
7684
+ diff_summary TEXT
7685
+ );
7686
+ CREATE VIRTUAL TABLE IF NOT EXISTS governance_fts USING fts5(
7687
+ source,
7688
+ record_id,
7689
+ text,
7690
+ timestamp
7691
+ );
7692
+ `);
7693
+ }
7694
+ close() {
7695
+ if (this.db) {
7696
+ this.db.close();
7697
+ this.db = null;
7698
+ }
7699
+ }
7700
+ async loadFromDisk(cwd) {
7701
+ if (!this.db) {
7702
+ throw new Error("GovernanceSqliteView not initialized. Call init() first.");
7703
+ }
7704
+ const stats = {
7705
+ tasks: 0,
7706
+ completedTasks: 0,
7707
+ handoffs: 0,
7708
+ decisions: 0,
7709
+ architecture: false
7710
+ };
7711
+ this.db.exec("DELETE FROM governance_fts; DELETE FROM architecture; DELETE FROM tasks; DELETE FROM completed_tasks; DELETE FROM handoffs; DELETE FROM decisions;");
7712
+ const archPath = join18(cwd, ARCH_PATH);
7713
+ if (existsSync18(archPath)) {
7714
+ const raw = readFileSync6(archPath, "utf-8");
7715
+ const parsed = matter3(raw);
7716
+ const data = parsed.data;
7717
+ const versionRaw = data["version"];
7718
+ const version = typeof versionRaw === "number" ? versionRaw : typeof versionRaw === "string" ? Number.parseFloat(versionRaw) : null;
7719
+ const archId = "architecture";
7720
+ const content = parsed.content.trim();
7721
+ this.db.prepare(
7722
+ `INSERT OR REPLACE INTO architecture (id, version, last_updated, updated_by, change_reason, content)
7723
+ VALUES (?, ?, ?, ?, ?, ?)`
7724
+ ).run(
7725
+ archId,
7726
+ Number.isFinite(version) ? version : null,
7727
+ typeof data["last_updated"] === "string" ? data["last_updated"] : null,
7728
+ typeof data["updated_by"] === "string" ? data["updated_by"] : null,
7729
+ typeof data["change_reason"] === "string" ? data["change_reason"] : null,
7730
+ content
7731
+ );
7732
+ this.db.prepare(
7733
+ `INSERT INTO governance_fts (source, record_id, text, timestamp)
7734
+ VALUES (?, ?, ?, ?)`
7735
+ ).run("architecture", archId, content, typeof data["last_updated"] === "string" ? data["last_updated"] : null);
7736
+ stats.architecture = true;
7737
+ }
7738
+ const tasksPath = join18(cwd, TASKS_PATH);
7739
+ if (existsSync18(tasksPath)) {
7740
+ const raw = readFileSync6(tasksPath, "utf-8");
7741
+ const tasks = JSON.parse(raw);
7742
+ const insertTask = this.db.prepare(
7743
+ `INSERT OR REPLACE INTO tasks (id, description, status, created_at, updated_at, notes)
7744
+ VALUES (?, ?, ?, ?, ?, ?)`
7745
+ );
7746
+ const insertFts = this.db.prepare(
7747
+ `INSERT INTO governance_fts (source, record_id, text, timestamp)
7748
+ VALUES (?, ?, ?, ?)`
7749
+ );
7750
+ for (const task of tasks) {
7751
+ insertTask.run(task.id, task.description, task.status, task.created_at, task.updated_at ?? null, task.notes ?? null);
7752
+ insertFts.run("task", task.id, task.description + (task.notes ? `
7753
+ ${task.notes}` : ""), task.updated_at ?? task.created_at);
7754
+ stats.tasks += 1;
7755
+ }
7756
+ }
7757
+ const completedPath = join18(cwd, COMPLETED_PATH);
7758
+ if (existsSync18(completedPath)) {
7759
+ const lines = readFileSync6(completedPath, "utf-8").split("\n").filter((line) => line.trim().length > 0);
7760
+ const insertCompleted = this.db.prepare(
7761
+ `INSERT OR REPLACE INTO completed_tasks (id, description, status, created_at, updated_at, notes)
7762
+ VALUES (?, ?, ?, ?, ?, ?)`
7763
+ );
7764
+ const insertFts = this.db.prepare(
7765
+ `INSERT INTO governance_fts (source, record_id, text, timestamp)
7766
+ VALUES (?, ?, ?, ?)`
7767
+ );
7768
+ for (const line of lines) {
7769
+ const task = JSON.parse(line);
7770
+ insertCompleted.run(task.id, task.description, task.status, task.created_at, task.updated_at ?? null, task.notes ?? null);
7771
+ insertFts.run("completed_task", task.id, task.description + (task.notes ? `
7772
+ ${task.notes}` : ""), task.updated_at ?? task.created_at);
7773
+ stats.completedTasks += 1;
7774
+ }
7775
+ }
7776
+ const handoffsPath = join18(cwd, HANDOFFS_PATH);
7777
+ if (existsSync18(handoffsPath)) {
7778
+ const lines = readFileSync6(handoffsPath, "utf-8").split("\n").filter((line) => line.trim().length > 0);
7779
+ const insertHandoff = this.db.prepare(
7780
+ `INSERT OR REPLACE INTO handoffs (id, timestamp, from_agent, reason, summary, next_actions)
7781
+ VALUES (?, ?, ?, ?, ?, ?)`
7782
+ );
7783
+ const insertFts = this.db.prepare(
7784
+ `INSERT INTO governance_fts (source, record_id, text, timestamp)
7785
+ VALUES (?, ?, ?, ?)`
7786
+ );
7787
+ for (const line of lines) {
7788
+ const entry = JSON.parse(line);
7789
+ const id = `${entry.timestamp}-${entry.from_agent ?? "unknown"}`;
7790
+ const nextActions = entry.next_actions.join("\n");
7791
+ insertHandoff.run(id, entry.timestamp, entry.from_agent ?? null, entry.reason, entry.summary, nextActions);
7792
+ insertFts.run("handoff", id, `${entry.summary}
7793
+ ${nextActions}`, entry.timestamp);
7794
+ stats.handoffs += 1;
7795
+ }
7796
+ }
7797
+ const decisionsPath = join18(cwd, DECISIONS_PATH);
7798
+ if (existsSync18(decisionsPath)) {
7799
+ const lines = readFileSync6(decisionsPath, "utf-8").split("\n").filter((line) => line.trim().length > 0);
7800
+ const insertDecision = this.db.prepare(
7801
+ `INSERT OR REPLACE INTO decisions (id, timestamp, category, change_reason, updated_by, diff_summary)
7802
+ VALUES (?, ?, ?, ?, ?, ?)`
7803
+ );
7804
+ const insertFts = this.db.prepare(
7805
+ `INSERT INTO governance_fts (source, record_id, text, timestamp)
7806
+ VALUES (?, ?, ?, ?)`
7807
+ );
7808
+ for (const line of lines) {
7809
+ const entry = JSON.parse(line);
7810
+ const id = `${entry.timestamp}-${entry.category}`;
7811
+ insertDecision.run(
7812
+ id,
7813
+ entry.timestamp,
7814
+ entry.category,
7815
+ entry.change_reason,
7816
+ entry.updated_by ?? null,
7817
+ entry.diff_summary ?? null
7818
+ );
7819
+ insertFts.run("decision", id, `${entry.change_reason}${entry.diff_summary ? `
7820
+ ${entry.diff_summary}` : ""}`, entry.timestamp);
7821
+ stats.decisions += 1;
7822
+ }
7823
+ }
7824
+ return stats;
7825
+ }
7826
+ search(query, limit = 10) {
7827
+ if (!this.db) {
7828
+ throw new Error("GovernanceSqliteView not initialized. Call init() first.");
7829
+ }
7830
+ const rows = this.db.prepare(
7831
+ `SELECT source, record_id as recordId, text, timestamp, rank
7832
+ FROM governance_fts
7833
+ WHERE governance_fts MATCH ?
7834
+ ORDER BY rank
7835
+ LIMIT ?`
7836
+ ).all(query, limit);
7837
+ return rows;
7838
+ }
7839
+ listTasks(status2) {
7840
+ if (!this.db) {
7841
+ throw new Error("GovernanceSqliteView not initialized. Call init() first.");
7842
+ }
7843
+ if (status2) {
7844
+ return this.db.prepare(
7845
+ "SELECT id, description, status, created_at, updated_at, notes FROM tasks WHERE status = ? ORDER BY created_at"
7846
+ ).all(status2);
7847
+ }
7848
+ return this.db.prepare(
7849
+ "SELECT id, description, status, created_at, updated_at, notes FROM tasks ORDER BY created_at"
7850
+ ).all();
7851
+ }
7852
+ getLatestHandoff() {
7853
+ if (!this.db) {
7854
+ throw new Error("GovernanceSqliteView not initialized. Call init() first.");
7855
+ }
7856
+ const row = this.db.prepare(
7857
+ "SELECT timestamp, from_agent as fromAgent, reason, summary, next_actions as nextActions FROM handoffs ORDER BY timestamp DESC LIMIT 1"
7858
+ ).get();
7859
+ if (!row) return null;
7860
+ return {
7861
+ timestamp: row.timestamp,
7862
+ from_agent: row.fromAgent ?? void 0,
7863
+ reason: row.reason,
7864
+ summary: row.summary,
7865
+ next_actions: row.nextActions.split("\n").filter((item) => item.trim().length > 0)
7866
+ };
7867
+ }
7868
+ getArchitecture() {
7869
+ if (!this.db) {
7870
+ throw new Error("GovernanceSqliteView not initialized. Call init() first.");
7871
+ }
7872
+ const row = this.db.prepare(
7873
+ "SELECT version, last_updated, updated_by, change_reason, content FROM architecture LIMIT 1"
7874
+ ).get();
7875
+ if (!row) return null;
7876
+ return {
7877
+ content: row.content,
7878
+ meta: {
7879
+ version: row.version,
7880
+ last_updated: row.last_updated,
7881
+ updated_by: row.updated_by,
7882
+ change_reason: row.change_reason
7883
+ }
7884
+ };
7885
+ }
7886
+ };
7634
7887
 
7635
7888
  // src/cli/governance.ts
7636
7889
  var ACTIVE_ARCH_PATH3 = join19(".archon", "active", "architecture.md");
@@ -7644,11 +7897,11 @@ function isTaskStatus(value) {
7644
7897
  }
7645
7898
  function resolveArchitecturePath2(cwd) {
7646
7899
  const agdPath = join19(cwd, ACTIVE_ARCH_PATH3);
7647
- if (existsSync18(agdPath)) {
7900
+ if (existsSync19(agdPath)) {
7648
7901
  return { path: agdPath, source: "agd" };
7649
7902
  }
7650
7903
  const legacyPath = join19(cwd, "ARCHITECTURE.md");
7651
- if (existsSync18(legacyPath)) {
7904
+ if (existsSync19(legacyPath)) {
7652
7905
  return { path: legacyPath, source: "legacy" };
7653
7906
  }
7654
7907
  return { path: null, source: null };
@@ -7736,9 +7989,9 @@ function createGovernanceCommand() {
7736
7989
  console.log(chalk17.yellow(" \u25CB No architecture file found"));
7737
7990
  }
7738
7991
  const tasksPath = join19(cwd, ACTIVE_TASKS_PATH2);
7739
- if (existsSync18(tasksPath)) {
7992
+ if (existsSync19(tasksPath)) {
7740
7993
  try {
7741
- const tasksRaw = JSON.parse(readFileSync6(tasksPath, "utf-8"));
7994
+ const tasksRaw = JSON.parse(readFileSync7(tasksPath, "utf-8"));
7742
7995
  const tasks2 = parseTasks(tasksRaw);
7743
7996
  if (tasks2) {
7744
7997
  renderStatusCounts(countTaskStatuses(tasks2));
@@ -7750,8 +8003,8 @@ function createGovernanceCommand() {
7750
8003
  }
7751
8004
  }
7752
8005
  const contextPath = join19(cwd, CURRENT_CONTEXT_PATH);
7753
- if (existsSync18(contextPath)) {
7754
- const content = readFileSync6(contextPath, "utf-8");
8006
+ if (existsSync19(contextPath)) {
8007
+ const content = readFileSync7(contextPath, "utf-8");
7755
8008
  const meta = parseContextMeta(content);
7756
8009
  console.log(chalk17.dim(` Handoff: ${meta.timestamp ?? "present"}`));
7757
8010
  if (meta.reason) {
@@ -7759,15 +8012,15 @@ function createGovernanceCommand() {
7759
8012
  }
7760
8013
  }
7761
8014
  const handoffHistoryPath = join19(cwd, HANDOFF_HISTORY_PATH);
7762
- if (existsSync18(handoffHistoryPath)) {
7763
- const count = lineCount(readFileSync6(handoffHistoryPath, "utf-8"));
8015
+ if (existsSync19(handoffHistoryPath)) {
8016
+ const count = lineCount(readFileSync7(handoffHistoryPath, "utf-8"));
7764
8017
  if (count > 0) {
7765
8018
  console.log(chalk17.dim(` Handoff entries: ${count}`));
7766
8019
  }
7767
8020
  }
7768
8021
  const completedPath = join19(cwd, COMPLETED_TASKS_PATH);
7769
- if (existsSync18(completedPath)) {
7770
- const count = lineCount(readFileSync6(completedPath, "utf-8"));
8022
+ if (existsSync19(completedPath)) {
8023
+ const count = lineCount(readFileSync7(completedPath, "utf-8"));
7771
8024
  if (count > 0) {
7772
8025
  console.log(chalk17.dim(` Completed tasks archived: ${count}`));
7773
8026
  }
@@ -7784,7 +8037,7 @@ function createGovernanceCommand() {
7784
8037
  return;
7785
8038
  }
7786
8039
  if (options.raw) {
7787
- const raw = readFileSync6(archInfo.path, "utf-8");
8040
+ const raw = readFileSync7(archInfo.path, "utf-8");
7788
8041
  console.log(raw.trimEnd());
7789
8042
  return;
7790
8043
  }
@@ -7801,7 +8054,7 @@ function createGovernanceCommand() {
7801
8054
  console.log(result.value);
7802
8055
  return;
7803
8056
  }
7804
- const legacyRaw = readFileSync6(archInfo.path, "utf-8");
8057
+ const legacyRaw = readFileSync7(archInfo.path, "utf-8");
7805
8058
  const legacyParsed = matter4(legacyRaw);
7806
8059
  const legacyContent = legacyParsed.content.trim();
7807
8060
  if (!legacyContent) {
@@ -7813,7 +8066,7 @@ function createGovernanceCommand() {
7813
8066
  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
8067
  const cwd = process.cwd();
7815
8068
  const filePath = options.file;
7816
- if (!existsSync18(filePath)) {
8069
+ if (!existsSync19(filePath)) {
7817
8070
  console.log(chalk17.red(`File not found: ${filePath}`));
7818
8071
  process.exit(1);
7819
8072
  }
@@ -7885,6 +8138,14 @@ function createGovernanceCommand() {
7885
8138
  }
7886
8139
  console.log("");
7887
8140
  });
8141
+ governance.command("sqlite-init").description("Initialize or refresh local governance SQLite DB").option("--db <path>", "Override DB path (default: .archon/governance.db)").action(async (options) => {
8142
+ const cwd = process.cwd();
8143
+ const view = new GovernanceSqliteView({ dbPath: options.db ?? ".archon/governance.db" });
8144
+ view.init(cwd);
8145
+ await view.loadFromDisk(cwd);
8146
+ view.close();
8147
+ console.log(chalk17.green("\u2713 Governance SQLite DB initialized"));
8148
+ });
7888
8149
  return governance;
7889
8150
  }
7890
8151
 
@@ -7914,11 +8175,11 @@ program.command("status").description("Show current user and project status").ac
7914
8175
  await status();
7915
8176
  });
7916
8177
  program.command("upgrade").description("Upgrade your tier (BYOK for free unlimited, or Managed plan)").action(async () => {
7917
- const { showUpgradeMenu } = await import("./tier-selection-426HA765.js");
8178
+ const { showUpgradeMenu } = await import("./tier-selection-XFBM4SZ4.js");
7918
8179
  await showUpgradeMenu();
7919
8180
  });
7920
8181
  program.command("pricing", { hidden: true }).action(async () => {
7921
- const { showUpgradeMenu } = await import("./tier-selection-426HA765.js");
8182
+ const { showUpgradeMenu } = await import("./tier-selection-XFBM4SZ4.js");
7922
8183
  await showUpgradeMenu();
7923
8184
  });
7924
8185
  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) => {
@@ -3,7 +3,7 @@ import {
3
3
  listKeys,
4
4
  removeKey,
5
5
  setPrimaryKey
6
- } from "./chunk-75J2JMU3.js";
6
+ } from "./chunk-JNFXMWBR.js";
7
7
  import "./chunk-TFSHS7EN.js";
8
8
  import "./chunk-RDG5BUED.js";
9
9
  import "./chunk-SVU7MLG6.js";
@@ -7,13 +7,13 @@ import {
7
7
  setPreference,
8
8
  showExecutionPreferences,
9
9
  showPreferences
10
- } from "./chunk-ZJXIOETW.js";
10
+ } from "./chunk-CTWVQ6F3.js";
11
11
  import "./chunk-UFR2LX6G.js";
12
12
  import "./chunk-TFSHS7EN.js";
13
13
  import "./chunk-RDG5BUED.js";
14
- import "./chunk-CZCY63EY.js";
14
+ import "./chunk-F4OUCZPN.js";
15
15
  import "./chunk-M4LGRTLC.js";
16
- import "./chunk-LBBHM4I5.js";
16
+ import "./chunk-GBYW3YAY.js";
17
17
  import "./chunk-SVU7MLG6.js";
18
18
  import "./chunk-4VNS5WPM.js";
19
19
  export {
@@ -4,7 +4,7 @@ import {
4
4
  showTierSwitchMenu,
5
5
  showUpgradeMenu,
6
6
  updateUserTier
7
- } from "./chunk-LBBHM4I5.js";
7
+ } from "./chunk-GBYW3YAY.js";
8
8
  import "./chunk-SVU7MLG6.js";
9
9
  import "./chunk-4VNS5WPM.js";
10
10
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "archondev",
3
- "version": "2.19.0",
3
+ "version": "2.19.2",
4
4
  "description": "Local-first AI-powered development governance system",
5
5
  "main": "dist/index.js",
6
6
  "bin": {