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/README.md +4 -0
- package/dist/{bug-DCFTT2AF.js → bug-IJCK43FK.js} +4 -4
- package/dist/{chunk-ESSNYHC7.js → chunk-ACFMKTDL.js} +5 -4
- package/dist/{chunk-2BCITFWP.js → chunk-DCIIYVJW.js} +2 -2
- package/dist/{chunk-HJARQDQR.js → chunk-EIEU3IIY.js} +9 -0
- package/dist/{chunk-HGLPIM7J.js → chunk-KG35EHZY.js} +1 -1
- package/dist/{chunk-BFPWDOMA.js → chunk-M6GNIN64.js} +1 -1
- package/dist/{chunk-OAHFRSDS.js → chunk-O3B6BE5D.js} +1 -1
- package/dist/{chunk-MRRA3QDP.js → chunk-OREGEFTF.js} +4 -4
- package/dist/{chunk-5CFGPXQ3.js → chunk-PCTP3LKJ.js} +1 -1
- package/dist/{chunk-5BYCJAFM.js → chunk-PJRQI5UN.js} +1 -1
- package/dist/{chunk-ICSHS6BW.js → chunk-QTBRLNZQ.js} +1 -1
- package/dist/{chunk-YFCC6QEY.js → chunk-YA562WHL.js} +1 -1
- package/dist/{code-review-6MU4UE5M.js → code-review-ODLXGXNZ.js} +2 -2
- package/dist/{execute-OTW55P2Q.js → execute-ZTJGSRBW.js} +5 -5
- package/dist/{geo-GEWH777F.js → geo-HRG7M7YX.js} +3 -3
- package/dist/index.js +947 -93
- package/dist/{interviewer-NQHNMVH4.js → interviewer-BWM5SNOE.js} +1 -1
- package/dist/{list-BJCKDRG4.js → list-REPLUXJF.js} +5 -5
- package/dist/{parallel-U3COBCHB.js → parallel-23VQYK7H.js} +5 -5
- package/dist/{plan-4RIHWWZG.js → plan-HCYXLSSD.js} +4 -4
- package/dist/{review-AUG6GIL6.js → review-F6DHAGDF.js} +3 -3
- package/package.json +1 -1
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-
|
|
7
|
+
} from "./chunk-O3B6BE5D.js";
|
|
8
8
|
import {
|
|
9
9
|
bugReport
|
|
10
|
-
} from "./chunk-
|
|
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-
|
|
23
|
-
import "./chunk-
|
|
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-
|
|
49
|
+
} from "./chunk-QTBRLNZQ.js";
|
|
50
50
|
import {
|
|
51
51
|
DependencyParser,
|
|
52
52
|
EnvironmentConfigLoader,
|
|
53
53
|
EnvironmentValidator,
|
|
54
54
|
execute
|
|
55
|
-
} from "./chunk-
|
|
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-
|
|
63
|
+
} from "./chunk-YA562WHL.js";
|
|
64
64
|
import {
|
|
65
65
|
listLocalAtoms,
|
|
66
66
|
loadAtom,
|
|
67
67
|
plan
|
|
68
|
-
} from "./chunk-
|
|
69
|
-
import "./chunk-
|
|
70
|
-
import "./chunk-
|
|
71
|
-
import
|
|
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
|
|
111
|
-
import
|
|
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:
|
|
431
|
-
await
|
|
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 (
|
|
1203
|
-
else if (
|
|
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")) &&
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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 =
|
|
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
|
|
3065
|
-
if (
|
|
3066
|
-
const parser = new ArchitectureParser(
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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 =
|
|
3400
|
+
info.hasArchitecture = resolveArchitecturePath(cwd).path !== null;
|
|
3344
3401
|
info.hasProgress = existsSync6(join6(cwd, "progress.txt"));
|
|
3345
3402
|
if (info.hasArchitecture) {
|
|
3346
|
-
const
|
|
3347
|
-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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 (
|
|
4275
|
+
} catch (err2) {
|
|
4176
4276
|
spinner.fail("Error fetching credits");
|
|
4177
|
-
console.error(
|
|
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 (
|
|
4331
|
+
} catch (err2) {
|
|
4232
4332
|
spinner.fail("Error preparing checkout");
|
|
4233
|
-
console.error(
|
|
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 (
|
|
4377
|
+
} catch (err2) {
|
|
4278
4378
|
spinner.fail("Error fetching history");
|
|
4279
|
-
console.error(
|
|
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 (
|
|
4459
|
+
} catch (err2) {
|
|
4360
4460
|
spinner.fail("Error managing budget");
|
|
4361
|
-
console.error(
|
|
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 (
|
|
4537
|
+
} catch (err2) {
|
|
4438
4538
|
spinner.fail("Error managing auto-recharge");
|
|
4439
|
-
console.error(
|
|
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 (
|
|
4592
|
+
} catch (err2) {
|
|
4493
4593
|
spinner.fail("Error fetching audit history");
|
|
4494
|
-
console.error(
|
|
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 (
|
|
5252
|
+
} catch (err2) {
|
|
5153
5253
|
spinner.fail("Error saving session");
|
|
5154
|
-
console.error(
|
|
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 (
|
|
5295
|
+
} catch (err2) {
|
|
5196
5296
|
spinner.fail("Error fetching sessions");
|
|
5197
|
-
console.error(
|
|
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 (
|
|
5346
|
+
} catch (err2) {
|
|
5247
5347
|
spinner.fail("Error resuming session");
|
|
5248
|
-
console.error(
|
|
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 (
|
|
5388
|
+
} catch (err2) {
|
|
5289
5389
|
spinner.fail("Error syncing session");
|
|
5290
|
-
console.error(
|
|
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 (
|
|
6424
|
+
} catch (err2) {
|
|
6325
6425
|
spinner.fail("Failed to freeze Constitution");
|
|
6326
|
-
console.error(
|
|
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
|
|
7006
|
-
console.log(chalk16.red(` - ${
|
|
7105
|
+
for (const err2 of result.parseErrors) {
|
|
7106
|
+
console.log(chalk16.red(` - ${err2}`));
|
|
7007
7107
|
}
|
|
7008
7108
|
}
|
|
7009
7109
|
console.log();
|
|
7010
|
-
} catch (
|
|
7011
|
-
console.log(chalk16.red(`Failed to run sync: ${
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
8100
|
+
console.error(chalk18.red("Invalid action. Use: enable, disable, or status"));
|
|
7247
8101
|
process.exit(1);
|
|
7248
8102
|
}
|
|
7249
8103
|
await cleanupAuto(action);
|