archondev 2.19.2 → 2.19.4

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
@@ -77,6 +77,7 @@ pnpm exec tsx scripts/init-governance-db.ts
77
77
  | `archon credits` | View credit balance |
78
78
  | `archon credits add` | Purchase credits |
79
79
  | `archon credits budget` | Set monthly budget and alerts |
80
+ | `archon usage` | Usage by period and model (BYOK/Credits) |
80
81
  | `archon keys add <provider>` | Add your own API key — BYOK (Bring Your Own Key) |
81
82
  | `archon keys list` | Show configured API keys by provider |
82
83
  | `archon preferences` | Interactive settings menu (billing, models, keys, usage) |
@@ -117,6 +118,8 @@ pnpm exec tsx scripts/init-governance-db.ts
117
118
 
118
119
  **Notes:**
119
120
  - Credits tier shows your balance and per‑model usage on startup; use `archon credits` for full details and history.
121
+ - Content-only requests (stories, outlines, lessons, visuals) use lightweight planning to avoid blocking.
122
+ - BYOK shows per‑model usage and cost by today/week/month/year in `archon preferences` → “View usage details.”
120
123
  - You can paste multi‑line requests into interactive prompts; Archon captures them as a single response.
121
124
 
122
125
  **Tip:** Use `archon plan --edit` to adjust title and acceptance criteria before planning.
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  bugReport
3
- } from "./chunk-DCIIYVJW.js";
3
+ } from "./chunk-XKYRHJA5.js";
4
4
  import "./chunk-PCTP3LKJ.js";
5
5
  import "./chunk-PJRQI5UN.js";
6
6
  import "./chunk-EIEU3IIY.js";
@@ -6,7 +6,7 @@ import {
6
6
  import {
7
7
  listLocalAtoms,
8
8
  loadAtom
9
- } from "./chunk-ACFMKTDL.js";
9
+ } from "./chunk-IKMCIWK3.js";
10
10
  import {
11
11
  loadConfig
12
12
  } from "./chunk-SVU7MLG6.js";
@@ -4,7 +4,7 @@ import {
4
4
  analyzeProject,
5
5
  featuresToTasks,
6
6
  readArchitectureContext
7
- } from "./chunk-KG35EHZY.js";
7
+ } from "./chunk-YGDLWQBK.js";
8
8
 
9
9
  // src/cli/review.ts
10
10
  import chalk from "chalk";
@@ -593,6 +593,7 @@ async function reviewRun(options) {
593
593
  spinner.stop();
594
594
  console.log(chalk.green(`Starting AI Review`));
595
595
  console.log(chalk.dim(`Pending tasks: ${stats.pending}`));
596
+ console.log(chalk.dim("Workflow: Stage 1 spec compliance \u2192 Stage 2 code quality"));
596
597
  if (limit) {
597
598
  console.log(chalk.dim(`Limit: ${limit}`));
598
599
  }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  listLocalAtoms
3
- } from "./chunk-ACFMKTDL.js";
3
+ } from "./chunk-IKMCIWK3.js";
4
4
 
5
5
  // src/cli/list.ts
6
6
  import chalk from "chalk";
@@ -6,7 +6,7 @@ import {
6
6
  import {
7
7
  UsageRecorder,
8
8
  loadAtom
9
- } from "./chunk-ACFMKTDL.js";
9
+ } from "./chunk-IKMCIWK3.js";
10
10
  import {
11
11
  transitionAtom
12
12
  } from "./chunk-PCTP3LKJ.js";
@@ -4793,7 +4793,7 @@ function createPrompt() {
4793
4793
  }
4794
4794
  async function execute(atomId, options) {
4795
4795
  if (options.parallel && options.parallel.length > 0) {
4796
- const { parallelExecute } = await import("./parallel-23VQYK7H.js");
4796
+ const { parallelExecute } = await import("./parallel-QLKYSZZ3.js");
4797
4797
  const allAtomIds = [atomId, ...options.parallel];
4798
4798
  await parallelExecute(allAtomIds, { skipGates: options.skipGates === true });
4799
4799
  return;
@@ -4894,6 +4894,16 @@ Repository: ${repoUrl}`));
4894
4894
  console.log(chalk2.dim(`Run "archon plan" to create a plan first.`));
4895
4895
  process.exit(1);
4896
4896
  }
4897
+ const atomContext = atom.context;
4898
+ const designApproved = atomContext?.["designApproved"] === true;
4899
+ if (!designApproved) {
4900
+ console.log(chalk2.yellow("\n[!] This atom does not record explicit design approval metadata."));
4901
+ const proceed = await prompt.ask("Proceed with execution anyway? (y/N): ");
4902
+ if (proceed.trim().toLowerCase() !== "y") {
4903
+ console.log(chalk2.dim("Execution cancelled. Re-run planning and approve design first."));
4904
+ return;
4905
+ }
4906
+ }
4897
4907
  const archPath = join4(cwd, "ARCHITECTURE.md");
4898
4908
  if (!existsSync9(archPath)) {
4899
4909
  console.error(chalk2.red("ARCHITECTURE.md not found."));
@@ -851,6 +851,24 @@ async function plan(description, options) {
851
851
  requirements.length = 0;
852
852
  }
853
853
  }
854
+ const classification = classifyTaskIntent({
855
+ description,
856
+ requirements,
857
+ references,
858
+ deliverableTarget: deliverableTarget ?? void 0
859
+ });
860
+ const isContentOnlyTask = classification.kind === "content";
861
+ const designApproved = await promptForDesignApproval(prompt, {
862
+ description,
863
+ requirements,
864
+ references,
865
+ deliverableTarget: deliverableTarget ?? void 0,
866
+ classification
867
+ });
868
+ if (!designApproved) {
869
+ console.log(chalk.yellow("\nDesign not approved. Planning cancelled."));
870
+ return;
871
+ }
854
872
  console.log(chalk.dim("Creating atom from description..."));
855
873
  const atomInput = parseAtomDescription(description, options, requirements);
856
874
  const atom = createAtom(atomInput, {
@@ -858,7 +876,9 @@ async function plan(description, options) {
858
876
  fileSummaries,
859
877
  missingFiles,
860
878
  requirements,
861
- deliverableTarget
879
+ deliverableTarget,
880
+ designApproved,
881
+ designApprovalTimestamp: (/* @__PURE__ */ new Date()).toISOString()
862
882
  });
863
883
  const validation = validateAtom(atom);
864
884
  if (!validation.valid) {
@@ -872,6 +892,26 @@ async function plan(description, options) {
872
892
  Atom created: ${atom.externalId}`));
873
893
  console.log(chalk.dim(`Title: ${atom.title}`));
874
894
  console.log(chalk.dim(`Acceptance Criteria: ${atom.acceptanceCriteria.length} items`));
895
+ if (isContentOnlyTask) {
896
+ console.log(chalk.blue("\nContent task detected. Creating a lightweight plan (no adversarial loop)."));
897
+ atom.plan = buildContentPlan({
898
+ description,
899
+ requirements,
900
+ referencedFiles: references,
901
+ deliverableTarget,
902
+ missingFiles
903
+ });
904
+ atom.status = "READY";
905
+ await saveAtom(atom);
906
+ console.log(chalk.green(`
907
+ \u2705 Atom saved: ${atom.externalId}`));
908
+ console.log(chalk.dim(`Status: ${atom.status}`));
909
+ console.log(chalk.dim(`
910
+ Next steps:`));
911
+ console.log(chalk.dim(` - Execute: archon execute ${atom.externalId}`));
912
+ console.log(chalk.dim(` - View: archon show ${atom.externalId}`));
913
+ return;
914
+ }
875
915
  let apiKey = process.env["ANTHROPIC_API_KEY"];
876
916
  if (!apiKey) {
877
917
  const keyManager = new KeyManager();
@@ -926,15 +966,65 @@ Atom saved: ${atom.externalId}`));
926
966
  }
927
967
  }
928
968
  }
969
+ const shouldAutoFallback = shouldFallbackToContentPlan({
970
+ classification,
971
+ description,
972
+ issues: planResult.iterations.flatMap(
973
+ (iteration) => iteration.validation.passed ? [] : iteration.validation.issues.map((issue) => issue.message)
974
+ )
975
+ });
976
+ if (shouldAutoFallback) {
977
+ console.log(chalk.blue("\nTask looks content-focused. Switching to lightweight plan."));
978
+ atom.plan = buildContentPlan({
979
+ description,
980
+ requirements,
981
+ referencedFiles: references,
982
+ deliverableTarget,
983
+ missingFiles
984
+ });
985
+ atom.status = "READY";
986
+ await saveAtom(atom);
987
+ console.log(chalk.green(`
988
+ \u2705 Atom saved: ${atom.externalId}`));
989
+ console.log(chalk.dim(`Status: ${atom.status}`));
990
+ console.log(chalk.dim(`
991
+ Next steps:`));
992
+ console.log(chalk.dim(` - Execute: archon execute ${atom.externalId}`));
993
+ console.log(chalk.dim(` - View: archon show ${atom.externalId}`));
994
+ return;
995
+ }
929
996
  const answer2 = await prompt.ask("\nSave as draft anyway? (y/N): ");
930
- if (answer2.toLowerCase() !== "y") {
997
+ const normalized = answer2.toLowerCase();
998
+ if (normalized.includes("wrong") || normalized.includes("content") || normalized.includes("not a code")) {
999
+ console.log(chalk.blue("\nReclassifying as content task and creating a lightweight plan."));
1000
+ atom.plan = buildContentPlan({
1001
+ description,
1002
+ requirements,
1003
+ referencedFiles: references,
1004
+ deliverableTarget,
1005
+ missingFiles
1006
+ });
1007
+ atom.status = "READY";
1008
+ await saveAtom(atom);
1009
+ console.log(chalk.green(`
1010
+ \u2705 Atom saved: ${atom.externalId}`));
1011
+ console.log(chalk.dim(`Status: ${atom.status}`));
1012
+ console.log(chalk.dim(`
1013
+ Next steps:`));
1014
+ console.log(chalk.dim(` - Execute: archon execute ${atom.externalId}`));
1015
+ console.log(chalk.dim(` - View: archon show ${atom.externalId}`));
1016
+ return;
1017
+ }
1018
+ if (normalized !== "y") {
931
1019
  console.log(chalk.dim("Atom discarded."));
932
1020
  return;
933
1021
  }
934
1022
  }
935
1023
  if (planResult.finalPlan) {
1024
+ const enrichedPlan = enforcePlanStructure(planResult.finalPlan, requirements);
1025
+ planResult.finalPlan = enrichedPlan;
936
1026
  console.log(chalk.green("\n\u2705 Plan approved!"));
937
- displayPlan(planResult.finalPlan);
1027
+ displayPlan(enrichedPlan);
938
1028
  } else {
939
1029
  console.log(chalk.yellow("\nNo approved plan available."));
940
1030
  }
@@ -1029,6 +1119,163 @@ function extractNumberedRequirements(description) {
1029
1119
  }
1030
1120
  return requirements;
1031
1121
  }
1122
+ function extractNumberedSteps(description) {
1123
+ const steps = [];
1124
+ const lines = description.split("\n");
1125
+ for (const line of lines) {
1126
+ const match = line.match(/^\s*(\d+)[\).]\s+(.+)$/);
1127
+ if (match && match[2]) {
1128
+ steps.push(match[2].trim());
1129
+ }
1130
+ }
1131
+ return steps;
1132
+ }
1133
+ async function promptForDesignApproval(prompt, input) {
1134
+ console.log(chalk.blue("\nDesign Approval Gate"));
1135
+ console.log(chalk.dim("\u2500".repeat(40)));
1136
+ console.log(chalk.dim(`Task type: ${input.classification.kind} (${input.classification.confidence} confidence)`));
1137
+ console.log(chalk.dim(`Title: ${deriveTitle(input.description)}`));
1138
+ if (input.requirements.length > 0) {
1139
+ console.log(chalk.dim("\nRequirements summary:"));
1140
+ for (const req of input.requirements.slice(0, 6)) {
1141
+ console.log(chalk.dim(` - ${req}`));
1142
+ }
1143
+ if (input.requirements.length > 6) {
1144
+ console.log(chalk.dim(` - ... and ${input.requirements.length - 6} more`));
1145
+ }
1146
+ }
1147
+ if (input.references.length > 0) {
1148
+ console.log(chalk.dim("\nReferenced inputs:"));
1149
+ for (const ref of input.references.slice(0, 8)) {
1150
+ console.log(chalk.dim(` - ${ref}`));
1151
+ }
1152
+ }
1153
+ if (input.deliverableTarget) {
1154
+ console.log(chalk.dim(`
1155
+ Deliverable target: ${input.deliverableTarget}`));
1156
+ }
1157
+ console.log(chalk.dim("\nI will generate a step-by-step implementation plan from this design."));
1158
+ const approval = await prompt.ask("Approve design and proceed to planning? (Y/n): ");
1159
+ return approval.trim().toLowerCase() !== "n";
1160
+ }
1161
+ function enforcePlanStructure(plan2, requirements) {
1162
+ const normalizedSteps = plan2.steps.map((step, index) => {
1163
+ const trimmed = step.trim();
1164
+ if (/^step\s+\d+/i.test(trimmed)) {
1165
+ return trimmed;
1166
+ }
1167
+ return `Step ${index + 1}: ${trimmed}`;
1168
+ });
1169
+ const hasVerificationStep = normalizedSteps.some(
1170
+ (step) => /(verify|test|lint|build|validate|check)/i.test(step)
1171
+ );
1172
+ const hasAcceptanceStep = normalizedSteps.some(
1173
+ (step) => /(acceptance criteria|acceptance check|confirm criteria)/i.test(step)
1174
+ );
1175
+ if (!hasVerificationStep) {
1176
+ normalizedSteps.push("Step " + (normalizedSteps.length + 1) + ": Run verification commands (build/test/lint as applicable).");
1177
+ }
1178
+ if (!hasAcceptanceStep) {
1179
+ normalizedSteps.push(
1180
+ "Step " + (normalizedSteps.length + 1) + ": Confirm all acceptance criteria are satisfied before execution completion."
1181
+ );
1182
+ }
1183
+ const normalizedRisks = [...plan2.risks];
1184
+ if (!normalizedRisks.some((risk) => /scope/i.test(risk))) {
1185
+ normalizedRisks.push("Scope drift risk: avoid adding unrequested behavior.");
1186
+ }
1187
+ if (requirements.length > 0 && !normalizedRisks.some((risk) => /acceptance/i.test(risk))) {
1188
+ normalizedRisks.push("Acceptance mismatch risk: validate changes directly against requested criteria.");
1189
+ }
1190
+ return {
1191
+ ...plan2,
1192
+ steps: normalizedSteps,
1193
+ risks: normalizedRisks
1194
+ };
1195
+ }
1196
+ function classifyTaskIntent(input) {
1197
+ const text = `${input.description}
1198
+ ${input.requirements.join("\n")}`.toLowerCase();
1199
+ const signals = [];
1200
+ let contentScore = 0;
1201
+ let codeScore = 0;
1202
+ const contentCues = [
1203
+ /story|storytelling|storyboard|capsule|lesson|outline|narrative|plot|arc|character|conflict/,
1204
+ /illustration|visual|image|diagram|slides?|deck/,
1205
+ /write|draft|summarize|summarise|rewrite|edit|revise|polish/,
1206
+ /teach|teaching|curriculum|learning objectives?|lesson plan/
1207
+ ];
1208
+ const codeCues = [
1209
+ /api|endpoint|server|backend|frontend|cli|database|schema|migration/,
1210
+ /typescript|javascript|python|go|rust|java|c\+\+|react|node/,
1211
+ /implement|refactor|compile|build|deploy|test|lint|ci/
1212
+ ];
1213
+ for (const cue of contentCues) {
1214
+ if (cue.test(text)) {
1215
+ contentScore += 2;
1216
+ signals.push(`content:${cue.source}`);
1217
+ }
1218
+ }
1219
+ for (const cue of codeCues) {
1220
+ if (cue.test(text)) {
1221
+ codeScore += 2;
1222
+ signals.push(`code:${cue.source}`);
1223
+ }
1224
+ }
1225
+ const references = [...input.references];
1226
+ if (input.deliverableTarget) references.push(input.deliverableTarget);
1227
+ const contentRefs = references.filter((ref) => /\.(md|markdown|txt|rtf|pdf|png|jpg|jpeg|gif|svg|webp)$/i.test(ref));
1228
+ const codeRefs = references.filter((ref) => /\.(ts|tsx|js|jsx|mjs|cjs|py|go|rs|java|kt|cpp|c|h|sql|json|yml|yaml)$/i.test(ref));
1229
+ if (contentRefs.length > 0 && codeRefs.length === 0) {
1230
+ contentScore += 2;
1231
+ signals.push("content:refs");
1232
+ }
1233
+ if (codeRefs.length > 0) {
1234
+ codeScore += 2;
1235
+ signals.push("code:refs");
1236
+ }
1237
+ let kind = "mixed";
1238
+ let confidence = "low";
1239
+ if (contentScore >= 4 && contentScore >= codeScore + 2) {
1240
+ kind = "content";
1241
+ confidence = contentScore >= 6 ? "high" : "medium";
1242
+ } else if (codeScore >= 4 && codeScore >= contentScore + 2) {
1243
+ kind = "code";
1244
+ confidence = codeScore >= 6 ? "high" : "medium";
1245
+ }
1246
+ return { kind, confidence, contentScore, codeScore, signals };
1247
+ }
1248
+ function shouldFallbackToContentPlan(input) {
1249
+ if (input.classification.kind === "content") return true;
1250
+ const text = input.description.toLowerCase();
1251
+ const issueText = input.issues.join(" ").toLowerCase();
1252
+ const contentLike = /story|storytelling|capsule|lesson|outline|storyboard|illustration|visual|image/.test(text);
1253
+ const engineeringBlockers = /api|pipeline|module|interfaces|schema|database|timeout|rate limit|retry|cache|rollback|tests?/.test(issueText);
1254
+ if (contentLike && engineeringBlockers && input.classification.contentScore >= input.classification.codeScore) {
1255
+ return true;
1256
+ }
1257
+ return false;
1258
+ }
1259
+ function buildContentPlan(input) {
1260
+ const stepsFromNumbering = extractNumberedSteps(input.description);
1261
+ const stepsFromRequirements = input.requirements.map((req) => `Create: ${req}`);
1262
+ const steps = stepsFromNumbering.length > 0 ? stepsFromNumbering : stepsFromRequirements.length > 0 ? stepsFromRequirements : ["Draft a clear outline", "Write the content", "Review and refine", "Finalize deliverable"];
1263
+ const files = /* @__PURE__ */ new Set();
1264
+ input.referencedFiles.forEach((f) => files.add(f));
1265
+ if (input.deliverableTarget) files.add(input.deliverableTarget);
1266
+ const risks = [];
1267
+ if (input.missingFiles.length > 0) {
1268
+ risks.push(`Missing inputs: ${input.missingFiles.join(", ")}`);
1269
+ }
1270
+ risks.push("Source material may be incomplete; validate against lesson content.");
1271
+ return {
1272
+ steps,
1273
+ files_to_modify: Array.from(files),
1274
+ dependencies: [],
1275
+ risks,
1276
+ estimated_complexity: steps.length > 6 ? "MEDIUM" : "LOW"
1277
+ };
1278
+ }
1032
1279
  function extractReferencedFiles(description) {
1033
1280
  const references = /* @__PURE__ */ new Set();
1034
1281
  const barePattern = /\b[\w./-]+\.(md|txt|json|yaml|yml|png|jpg|jpeg|gif|svg|pdf)\b/gi;
@@ -1,3 +1,6 @@
1
+ import {
2
+ createAuthedSupabaseClient
3
+ } from "./chunk-Q3GIFHIQ.js";
1
4
  import {
2
5
  findModel,
3
6
  getAllActiveModels,
@@ -15,6 +18,10 @@ import {
15
18
  import {
16
19
  login
17
20
  } from "./chunk-F4OUCZPN.js";
21
+ import {
22
+ SUPABASE_ANON_KEY,
23
+ SUPABASE_URL
24
+ } from "./chunk-M4LGRTLC.js";
18
25
  import {
19
26
  getApiUrl,
20
27
  getAuthToken,
@@ -783,7 +790,7 @@ async function interactiveSettings() {
783
790
  await interactiveSettings();
784
791
  break;
785
792
  case "4":
786
- await viewUsageDetails();
793
+ await showUsageDetails();
787
794
  await interactiveSettings();
788
795
  break;
789
796
  case "5":
@@ -1083,11 +1090,12 @@ async function manageApiKeys() {
1083
1090
  await addKey(provider);
1084
1091
  }
1085
1092
  }
1086
- async function viewUsageDetails() {
1093
+ async function showUsageDetails() {
1087
1094
  console.log(chalk.bold("\n-- Usage Details --\n"));
1088
1095
  const spinner = ora("Loading usage data...").start();
1089
1096
  const config = await loadConfig();
1090
1097
  const authToken = getAuthToken(config);
1098
+ const authId = config.userId;
1091
1099
  if (!authToken) {
1092
1100
  spinner.fail("Not logged in");
1093
1101
  return;
@@ -1103,36 +1111,112 @@ async function viewUsageDetails() {
1103
1111
  return;
1104
1112
  }
1105
1113
  const data = await response.json();
1106
- console.log(chalk.blue("Current Billing Period:"));
1107
- console.log(` ${data.periodStart} to ${data.periodEnd}`);
1108
- console.log();
1109
- console.log(chalk.blue("Token Usage:"));
1110
- console.log(` Input: ${formatTokens(data.totalInputTokens)} tokens`);
1111
- console.log(` Output: ${formatTokens(data.totalOutputTokens)} tokens`);
1112
- console.log(` Total: ${formatTokens(data.totalInputTokens + data.totalOutputTokens)} tokens`);
1113
- console.log();
1114
- console.log(chalk.blue("Cost:"));
1115
- console.log(` Base Cost: ${formatCost(data.totalBaseCost)}`);
1116
- if (data.tier === "CREDITS") {
1117
- const withFee = data.totalBaseCost * 1.1;
1118
- console.log(` With 10% Fee: ${formatCost(withFee)}`);
1119
- } else if (data.tier === "BYOK") {
1120
- console.log(chalk.dim(" (Paid directly to your provider)"));
1121
- }
1122
- if (data.byModel && Object.keys(data.byModel).length > 0) {
1123
- console.log();
1124
- console.log(chalk.blue("By Model:"));
1125
- for (const [model, stats] of Object.entries(data.byModel)) {
1126
- const modelInfo = findModel(model);
1127
- const name = modelInfo?.name ?? model;
1128
- console.log(` ${name}: ${formatTokens(stats.inputTokens + stats.outputTokens)} tokens (${formatCost(stats.cost)})`);
1114
+ if (data.tier === "BYOK") {
1115
+ if (!authId) {
1116
+ console.log(chalk.yellow("Unable to resolve user ID for usage details."));
1117
+ return;
1129
1118
  }
1130
- }
1131
- if (data.byOperation && Object.keys(data.byOperation).length > 0) {
1119
+ const supabase = createAuthedSupabaseClient(SUPABASE_URL, SUPABASE_ANON_KEY, authToken);
1120
+ const { data: profileRow, error: profileError } = await supabase.from("user_profiles").select("id").eq("auth_id", authId).single();
1121
+ if (profileError || !profileRow?.id) {
1122
+ console.log(chalk.yellow("Unable to resolve profile for usage details."));
1123
+ return;
1124
+ }
1125
+ const profileId = profileRow.id;
1126
+ const now = /* @__PURE__ */ new Date();
1127
+ const yearStart = new Date(now.getFullYear(), 0, 1);
1128
+ const { data: usageRows, error } = await supabase.from("token_usage").select("model, input_tokens, output_tokens, base_cost, created_at").eq("user_id", profileId).gte("created_at", yearStart.toISOString()).lte("created_at", now.toISOString());
1129
+ if (error || !usageRows) {
1130
+ console.log(chalk.yellow("Unable to fetch BYOK usage data."));
1131
+ return;
1132
+ }
1133
+ const rows = usageRows;
1134
+ const startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate());
1135
+ const startOfWeek = new Date(now.getFullYear(), now.getMonth(), now.getDate() - now.getDay());
1136
+ const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
1137
+ const periods = [
1138
+ { label: "Today", start: startOfToday, end: now },
1139
+ { label: "Week to Date (Sun\u2013Sat)", start: startOfWeek, end: now },
1140
+ { label: "Month to Date", start: startOfMonth, end: now },
1141
+ { label: "Year to Date", start: yearStart, end: now }
1142
+ ];
1143
+ const aggregate = (start, end) => {
1144
+ let totalInputTokens = 0;
1145
+ let totalOutputTokens = 0;
1146
+ let totalCost = 0;
1147
+ const byModelMap = /* @__PURE__ */ new Map();
1148
+ for (const row of rows) {
1149
+ const ts = new Date(row.created_at);
1150
+ if (ts < start || ts > end) continue;
1151
+ totalInputTokens += row.input_tokens;
1152
+ totalOutputTokens += row.output_tokens;
1153
+ totalCost += row.base_cost;
1154
+ const existing = byModelMap.get(row.model);
1155
+ if (existing) {
1156
+ existing.inputTokens += row.input_tokens;
1157
+ existing.outputTokens += row.output_tokens;
1158
+ existing.cost += row.base_cost;
1159
+ } else {
1160
+ byModelMap.set(row.model, {
1161
+ inputTokens: row.input_tokens,
1162
+ outputTokens: row.output_tokens,
1163
+ cost: row.base_cost
1164
+ });
1165
+ }
1166
+ }
1167
+ const byModel = Array.from(byModelMap.entries()).map(([model, stats]) => ({ model, ...stats })).sort((a, b) => b.cost - a.cost);
1168
+ return { totalInputTokens, totalOutputTokens, totalCost, byModel };
1169
+ };
1170
+ console.log(chalk.blue("BYOK Usage (local time):"));
1171
+ for (const period of periods) {
1172
+ const summary = aggregate(period.start, period.end);
1173
+ console.log();
1174
+ console.log(chalk.bold(`${period.label}:`));
1175
+ console.log(` ${period.start.toLocaleDateString()} \u2192 ${period.end.toLocaleDateString()}`);
1176
+ console.log(` Tokens: ${formatTokens(summary.totalInputTokens + summary.totalOutputTokens)} (in ${formatTokens(summary.totalInputTokens)} / out ${formatTokens(summary.totalOutputTokens)})`);
1177
+ console.log(` Cost: ${formatCost(summary.totalCost)} ${chalk.dim("(paid directly to provider)")}`);
1178
+ if (summary.byModel.length > 0) {
1179
+ console.log(chalk.dim(" By Model:"));
1180
+ for (const model of summary.byModel) {
1181
+ const modelInfo = findModel(model.model);
1182
+ const name = modelInfo?.name ?? model.model;
1183
+ const tokenTotal = model.inputTokens + model.outputTokens;
1184
+ console.log(` ${name}: ${formatTokens(tokenTotal)} tokens (${formatCost(model.cost)})`);
1185
+ }
1186
+ } else {
1187
+ console.log(chalk.dim(" No usage recorded."));
1188
+ }
1189
+ }
1190
+ } else {
1191
+ console.log(chalk.blue("Current Billing Period:"));
1192
+ console.log(` ${data.periodStart} to ${data.periodEnd}`);
1193
+ console.log();
1194
+ console.log(chalk.blue("Token Usage:"));
1195
+ console.log(` Input: ${formatTokens(data.totalInputTokens)} tokens`);
1196
+ console.log(` Output: ${formatTokens(data.totalOutputTokens)} tokens`);
1197
+ console.log(` Total: ${formatTokens(data.totalInputTokens + data.totalOutputTokens)} tokens`);
1132
1198
  console.log();
1133
- console.log(chalk.blue("By Operation:"));
1134
- for (const [op, stats] of Object.entries(data.byOperation)) {
1135
- console.log(` ${op}: ${formatTokens(stats.tokenCount)} tokens (${formatCost(stats.cost)})`);
1199
+ console.log(chalk.blue("Cost:"));
1200
+ console.log(` Base Cost: ${formatCost(data.totalBaseCost)}`);
1201
+ if (data.tier === "CREDITS") {
1202
+ const withFee = data.totalBaseCost * 1.1;
1203
+ console.log(` With 10% Fee: ${formatCost(withFee)}`);
1204
+ }
1205
+ if (data.byModel && data.byModel.length > 0) {
1206
+ console.log();
1207
+ console.log(chalk.blue("By Model:"));
1208
+ for (const stats of data.byModel) {
1209
+ const modelInfo = findModel(stats.model);
1210
+ const name = modelInfo?.name ?? stats.model;
1211
+ console.log(` ${name}: ${formatTokens(stats.inputTokens + stats.outputTokens)} tokens (${formatCost(stats.cost)})`);
1212
+ }
1213
+ }
1214
+ if (data.byOperation && data.byOperation.length > 0) {
1215
+ console.log();
1216
+ console.log(chalk.blue("By Operation:"));
1217
+ for (const stats of data.byOperation) {
1218
+ console.log(` ${stats.operation}: ${formatTokens(stats.tokenCount)} tokens (${formatCost(stats.cost)})`);
1219
+ }
1136
1220
  }
1137
1221
  }
1138
1222
  } catch {
@@ -1151,5 +1235,6 @@ export {
1151
1235
  setPreference,
1152
1236
  resetPreferences,
1153
1237
  listModels,
1154
- interactiveSettings
1238
+ interactiveSettings,
1239
+ showUsageDetails
1155
1240
  };
@@ -452,6 +452,24 @@ async function bugReport(title, options) {
452
452
  }
453
453
  const expectedBehavior = await prompt.ask(chalk.cyan("Expected behavior: "));
454
454
  const actualBehavior = await prompt.ask(chalk.cyan("Actual behavior: "));
455
+ const observedEvidence = await prompt.ask(
456
+ chalk.cyan("Observed evidence (logs/errors/metrics): ")
457
+ );
458
+ const reproducedInput = await prompt.ask(
459
+ chalk.cyan("Can you reproduce this consistently? (y/N): ")
460
+ );
461
+ const reproducedConsistently = reproducedInput.trim().toLowerCase() === "y";
462
+ const rootCauseHypothesis = await prompt.ask(
463
+ chalk.cyan("Root cause hypothesis (where/why failing): ")
464
+ );
465
+ if (!reproducedConsistently) {
466
+ console.log(chalk.yellow("\n[!] Root-cause-first workflow recommends reproducible steps before fixing."));
467
+ const continueChoice = await prompt.ask("Continue creating bug anyway? (y/N): ");
468
+ if (continueChoice.trim().toLowerCase() !== "y") {
469
+ console.log(chalk.dim("Bug report cancelled."));
470
+ return;
471
+ }
472
+ }
455
473
  let severity = null;
456
474
  while (!severity) {
457
475
  const severityInput = await prompt.ask(chalk.cyan("Severity (LOW/MEDIUM/HIGH/CRITICAL): "));
@@ -514,6 +532,7 @@ async function bugReport(title, options) {
514
532
  console.log(chalk.blue("\n\u{1F4E6} Creating fix atom..."));
515
533
  const acceptanceCriteria = [
516
534
  `Bug ${bug.id} is fixed`,
535
+ "Root cause evidence and hypothesis are documented before implementation",
517
536
  "Regression test added to prevent recurrence",
518
537
  "Typecheck passes",
519
538
  "All tests pass"
@@ -523,7 +542,17 @@ async function bugReport(title, options) {
523
542
  }
524
543
  const atom = createAtom({
525
544
  title: `Fix ${bug.id}: ${bug.title}`,
526
- description: buildAtomDescription(bug.id, bug.description, bug.actualBehavior, rcaResult),
545
+ description: buildAtomDescription(
546
+ bug.id,
547
+ bug.description,
548
+ bug.actualBehavior,
549
+ rcaResult,
550
+ {
551
+ observedEvidence,
552
+ rootCauseHypothesis,
553
+ reproducedConsistently
554
+ }
555
+ ),
527
556
  goals: [`Fix bug ${bug.id}`],
528
557
  acceptanceCriteria,
529
558
  ownershipPaths: rcaResult?.affectedFiles ?? triageResult.relatedFiles,
@@ -561,7 +590,7 @@ function formatSeverity(severity) {
561
590
  return chalk.green(severity);
562
591
  }
563
592
  }
564
- function buildAtomDescription(bugId, description, actualBehavior, rcaResult) {
593
+ function buildAtomDescription(bugId, description, actualBehavior, rcaResult, investigation) {
565
594
  const parts = [
566
595
  `Fix for ${bugId}`,
567
596
  "",
@@ -575,6 +604,11 @@ function buildAtomDescription(bugId, description, actualBehavior, rcaResult) {
575
604
  parts.push("");
576
605
  parts.push(`**Suggested Fix:** ${rcaResult.suggestedFix}`);
577
606
  }
607
+ parts.push("");
608
+ parts.push("**Root-Cause Investigation (Required Before Code Changes):**");
609
+ parts.push(`- Reproduced consistently: ${investigation.reproducedConsistently ? "yes" : "no"}`);
610
+ parts.push(`- Observed evidence: ${investigation.observedEvidence || "not provided"}`);
611
+ parts.push(`- Root cause hypothesis: ${investigation.rootCauseHypothesis || "not provided"}`);
578
612
  return parts.join("\n");
579
613
  }
580
614
  async function generateRCA(bugId, title, description, actualBehavior, affectedComponents) {
@@ -523,6 +523,9 @@ var ReviewerAgent = class {
523
523
  * Review a task by analyzing its associated files
524
524
  */
525
525
  async reviewTask(task, context) {
526
+ return this.reviewTaskByStage(task, context, "quality");
527
+ }
528
+ async reviewTaskByStage(task, context, stage) {
526
529
  const fileContents = await this.loadFilesForReview(task, context);
527
530
  if (fileContents.length === 0) {
528
531
  return {
@@ -538,7 +541,7 @@ var ReviewerAgent = class {
538
541
  usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0, baseCost: 0, markedUpCost: 0 }
539
542
  };
540
543
  }
541
- const userMessage = this.buildPrompt(task, fileContents, context);
544
+ const userMessage = this.buildPrompt(task, fileContents, context, stage);
542
545
  const response = await this.client.chat(SYSTEM_PROMPT, userMessage, {
543
546
  temperature: 0.3,
544
547
  maxTokens: 4096
@@ -569,7 +572,7 @@ var ReviewerAgent = class {
569
572
  /**
570
573
  * Build the review prompt
571
574
  */
572
- buildPrompt(task, files, context) {
575
+ buildPrompt(task, files, context, stage) {
573
576
  const parts = [];
574
577
  parts.push("# Review Task");
575
578
  parts.push(`**Feature:** ${task.featureName}`);
@@ -625,8 +628,16 @@ var ReviewerAgent = class {
625
628
  }
626
629
  parts.push("# Instructions");
627
630
  parts.push("");
628
- parts.push("Review these files against the specifications above.");
629
- parts.push("Identify any issues, bugs, security vulnerabilities, or deviations from requirements.");
631
+ if (stage === "spec") {
632
+ parts.push("Stage 1: SPEC COMPLIANCE REVIEW.");
633
+ parts.push("Focus strictly on whether implementation matches requested behavior and acceptance criteria.");
634
+ parts.push("Flag missing requirements, incorrect behavior, and unrequested scope additions.");
635
+ parts.push("Do not focus on style/performance unless it breaks requirements.");
636
+ } else {
637
+ parts.push("Stage 2: CODE QUALITY REVIEW (only after spec compliance).");
638
+ parts.push("Focus on correctness, security, maintainability, architecture boundaries, and test quality.");
639
+ parts.push("Do not re-open already-passed spec scope unless there is clear mismatch.");
640
+ }
630
641
  parts.push("Output your review as valid JSON.");
631
642
  return parts.join("\n");
632
643
  }
@@ -801,14 +812,39 @@ var ReviewService = class {
801
812
  architectureContent: this.architectureContent ?? void 0,
802
813
  maxFilesToRead: this.config.maxFilesPerTask ?? 10
803
814
  };
804
- const result = await this.agent.reviewTask(task, context);
815
+ const specResult = await this.agent.reviewTaskByStage(task, context, "spec");
816
+ if (!specResult.passesReview) {
817
+ const specUpdate = {
818
+ status: "needs_fix",
819
+ passesReview: false,
820
+ issuesFound: specResult.issues,
821
+ fixPriority: specResult.fixPriority,
822
+ fixPlan: specResult.fixPlan ?? "Resolve spec compliance issues before quality review.",
823
+ architectureImpact: specResult.architectureImpact ?? void 0,
824
+ reviewedAt: (/* @__PURE__ */ new Date()).toISOString(),
825
+ reviewedBy: "ai-reviewer-spec"
826
+ };
827
+ this.db.updateTask(task.id, specUpdate);
828
+ if (this.config.onTaskComplete) {
829
+ const updatedTask = this.db.getTask(task.id);
830
+ if (updatedTask) {
831
+ this.config.onTaskComplete(updatedTask, specResult);
832
+ }
833
+ }
834
+ return specResult;
835
+ }
836
+ const qualityResult = await this.agent.reviewTaskByStage(task, context, "quality");
837
+ const mergedResult = {
838
+ ...qualityResult,
839
+ usage: mergeUsage(specResult.usage, qualityResult.usage)
840
+ };
805
841
  const update = {
806
- status: result.passesReview ? "completed" : "needs_fix",
807
- passesReview: result.passesReview,
808
- issuesFound: result.issues,
809
- fixPriority: result.fixPriority,
810
- fixPlan: result.fixPlan ?? void 0,
811
- architectureImpact: result.architectureImpact ?? void 0,
842
+ status: mergedResult.passesReview ? "completed" : "needs_fix",
843
+ passesReview: mergedResult.passesReview,
844
+ issuesFound: mergedResult.issues,
845
+ fixPriority: mergedResult.fixPriority,
846
+ fixPlan: mergedResult.fixPlan ?? void 0,
847
+ architectureImpact: mergedResult.architectureImpact ?? void 0,
812
848
  reviewedAt: (/* @__PURE__ */ new Date()).toISOString(),
813
849
  reviewedBy: "ai-reviewer"
814
850
  };
@@ -816,12 +852,21 @@ var ReviewService = class {
816
852
  if (this.config.onTaskComplete) {
817
853
  const updatedTask = this.db.getTask(task.id);
818
854
  if (updatedTask) {
819
- this.config.onTaskComplete(updatedTask, result);
855
+ this.config.onTaskComplete(updatedTask, mergedResult);
820
856
  }
821
857
  }
822
- return result;
858
+ return mergedResult;
823
859
  }
824
860
  };
861
+ function mergeUsage(a, b) {
862
+ return {
863
+ inputTokens: a.inputTokens + b.inputTokens,
864
+ outputTokens: a.outputTokens + b.outputTokens,
865
+ totalTokens: a.totalTokens + b.totalTokens,
866
+ baseCost: a.baseCost + b.baseCost,
867
+ markedUpCost: a.markedUpCost + b.markedUpCost
868
+ };
869
+ }
825
870
 
826
871
  export {
827
872
  ReviewDatabase,
@@ -4,7 +4,7 @@ import {
4
4
  analyzeProject,
5
5
  featuresToTasks,
6
6
  readArchitectureContext
7
- } from "./chunk-KG35EHZY.js";
7
+ } from "./chunk-YGDLWQBK.js";
8
8
  import "./chunk-EIEU3IIY.js";
9
9
  import "./chunk-UFR2LX6G.js";
10
10
  import "./chunk-4VNS5WPM.js";
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  execute
3
- } from "./chunk-OREGEFTF.js";
3
+ } from "./chunk-HQBF3VTN.js";
4
4
  import "./chunk-EBHHIUCB.js";
5
- import "./chunk-ACFMKTDL.js";
5
+ import "./chunk-IKMCIWK3.js";
6
6
  import "./chunk-PCTP3LKJ.js";
7
7
  import "./chunk-PJRQI5UN.js";
8
8
  import "./chunk-EIEU3IIY.js";
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-O3B6BE5D.js";
8
8
  import {
9
9
  bugReport
10
- } from "./chunk-DCIIYVJW.js";
10
+ } from "./chunk-XKYRHJA5.js";
11
11
  import {
12
12
  reviewAnalyze,
13
13
  reviewExport,
@@ -19,15 +19,16 @@ import {
19
19
  reviewShow,
20
20
  reviewStatus,
21
21
  reviewUpdate
22
- } from "./chunk-M6GNIN64.js";
23
- import "./chunk-KG35EHZY.js";
22
+ } from "./chunk-6XLWTTGJ.js";
23
+ import "./chunk-YGDLWQBK.js";
24
24
  import {
25
25
  resetPreferences,
26
26
  setExecutionPreference,
27
27
  setPreference,
28
28
  showExecutionPreferences,
29
- showPreferences
30
- } from "./chunk-CTWVQ6F3.js";
29
+ showPreferences,
30
+ showUsageDetails
31
+ } from "./chunk-K3XN7PN6.js";
31
32
  import {
32
33
  a11yBadge,
33
34
  a11yCheck,
@@ -46,13 +47,13 @@ import {
46
47
  parallelRunWaves,
47
48
  parallelSchedule,
48
49
  parallelStatus
49
- } from "./chunk-QTBRLNZQ.js";
50
+ } from "./chunk-3UOMLERV.js";
50
51
  import {
51
52
  DependencyParser,
52
53
  EnvironmentConfigLoader,
53
54
  EnvironmentValidator,
54
55
  execute
55
- } from "./chunk-OREGEFTF.js";
56
+ } from "./chunk-HQBF3VTN.js";
56
57
  import {
57
58
  cloudCancel,
58
59
  cloudLogs,
@@ -60,12 +61,12 @@ import {
60
61
  } from "./chunk-EBHHIUCB.js";
61
62
  import {
62
63
  list
63
- } from "./chunk-YA562WHL.js";
64
+ } from "./chunk-C4HVI2NJ.js";
64
65
  import {
65
66
  listLocalAtoms,
66
67
  loadAtom,
67
68
  plan
68
- } from "./chunk-ACFMKTDL.js";
69
+ } from "./chunk-IKMCIWK3.js";
69
70
  import "./chunk-PCTP3LKJ.js";
70
71
  import "./chunk-PJRQI5UN.js";
71
72
  import {
@@ -3184,7 +3185,7 @@ async function handleNewProject(cwd, _state) {
3184
3185
  }
3185
3186
  if (intent.mode === "ad_hoc" && intent.confidence >= 0.7) {
3186
3187
  console.log(chalk6.dim("\n> Got it! Creating a task for this...\n"));
3187
- const { plan: plan2 } = await import("./plan-HCYXLSSD.js");
3188
+ const { plan: plan2 } = await import("./plan-7M27X3OD.js");
3188
3189
  await plan2(initialResponse, {});
3189
3190
  return;
3190
3191
  }
@@ -3208,7 +3209,7 @@ async function handleNewProject(cwd, _state) {
3208
3209
  break;
3209
3210
  case "2":
3210
3211
  console.log(chalk6.dim("\n> Creating a task for this...\n"));
3211
- const { plan: plan2 } = await import("./plan-HCYXLSSD.js");
3212
+ const { plan: plan2 } = await import("./plan-7M27X3OD.js");
3212
3213
  await plan2(initialResponse, {});
3213
3214
  break;
3214
3215
  case "3":
@@ -3238,7 +3239,7 @@ async function showNewProjectMenu(cwd) {
3238
3239
  case "3": {
3239
3240
  const description = await promptWithCommands("Describe what you want to do", { allowMultiline: true });
3240
3241
  if (description.trim()) {
3241
- const { plan: plan2 } = await import("./plan-HCYXLSSD.js");
3242
+ const { plan: plan2 } = await import("./plan-7M27X3OD.js");
3242
3243
  await plan2(description, {});
3243
3244
  }
3244
3245
  break;
@@ -3304,7 +3305,7 @@ async function runExploreFlow(cwd) {
3304
3305
  case "1": {
3305
3306
  const description = await promptWithCommands("Describe what you want to do", { allowMultiline: true });
3306
3307
  if (description.trim()) {
3307
- const { plan: plan2 } = await import("./plan-HCYXLSSD.js");
3308
+ const { plan: plan2 } = await import("./plan-7M27X3OD.js");
3308
3309
  await plan2(description, {});
3309
3310
  }
3310
3311
  break;
@@ -3566,7 +3567,7 @@ ${state.forbiddenPatterns?.length ? `- **Forbidden patterns:** ${state.forbidden
3566
3567
  if (continueChoice) {
3567
3568
  const description = await promptWithCommands("Describe what you want to build first", { allowMultiline: true });
3568
3569
  if (description.trim()) {
3569
- const { plan: plan2 } = await import("./plan-HCYXLSSD.js");
3570
+ const { plan: plan2 } = await import("./plan-7M27X3OD.js");
3570
3571
  await plan2(description, {});
3571
3572
  }
3572
3573
  }
@@ -3620,7 +3621,7 @@ async function handleAdaptExisting(cwd, state) {
3620
3621
  }
3621
3622
  if (intent.mode === "ad_hoc" && intent.confidence >= 0.7) {
3622
3623
  console.log(chalk6.dim("\n> Got it! Creating a task for this...\n"));
3623
- const { plan: plan2 } = await import("./plan-HCYXLSSD.js");
3624
+ const { plan: plan2 } = await import("./plan-7M27X3OD.js");
3624
3625
  await plan2(response, {});
3625
3626
  return;
3626
3627
  }
@@ -3651,7 +3652,7 @@ async function showAdaptExistingMenu(cwd, state) {
3651
3652
  case "2": {
3652
3653
  const description = await promptWithCommands("Describe what you want to do", { allowMultiline: true });
3653
3654
  if (description.trim()) {
3654
- const { plan: plan2 } = await import("./plan-HCYXLSSD.js");
3655
+ const { plan: plan2 } = await import("./plan-7M27X3OD.js");
3655
3656
  await plan2(description, {});
3656
3657
  }
3657
3658
  break;
@@ -3703,7 +3704,7 @@ async function analyzeAndAdapt(cwd) {
3703
3704
  async function codeReviewFirst(cwd) {
3704
3705
  console.log(chalk6.blue("\n-- Code Review Mode --\n"));
3705
3706
  console.log(chalk6.dim("I'll analyze your code for issues without making any changes.\n"));
3706
- const { reviewInit: reviewInit2, reviewAnalyze: reviewAnalyze2, reviewRun: reviewRun2 } = await import("./review-F6DHAGDF.js");
3707
+ const { reviewInit: reviewInit2, reviewAnalyze: reviewAnalyze2, reviewRun: reviewRun2 } = await import("./review-BXESOS5R.js");
3707
3708
  const reviewDbPath = join6(cwd, "docs", "code-review", "review-tasks.db");
3708
3709
  if (!existsSync6(reviewDbPath)) {
3709
3710
  await reviewInit2();
@@ -3799,10 +3800,26 @@ async function showMainMenu() {
3799
3800
  }
3800
3801
  console.log(chalk6.dim(' (Type "upgrade" or "help" anytime)'));
3801
3802
  console.log();
3802
- const selected = await promptWithCommands("Enter choice");
3803
+ const selected = await promptWithCommands("Enter choice", { allowMultiline: true });
3803
3804
  const choice = choices.find((c) => c.key === selected.toLowerCase());
3804
3805
  if (choice) {
3805
3806
  await choice.action();
3807
+ } else if (selected.trim()) {
3808
+ const freeform = selected.trim();
3809
+ const intent = detectUserIntent(freeform);
3810
+ if (intent.mode === "explore" && intent.confidence >= 0.7) {
3811
+ console.log(chalk6.dim("\n> Got it! Analyzing the project...\n"));
3812
+ await runExploreFlow(cwd);
3813
+ return;
3814
+ }
3815
+ if (intent.mode === "app_builder" && intent.confidence >= 0.7) {
3816
+ console.log(chalk6.dim("\n> Let me understand your project better...\n"));
3817
+ await runConversationalInterview(cwd, freeform);
3818
+ return;
3819
+ }
3820
+ console.log(chalk6.dim("\n> Got it! Creating a task for this...\n"));
3821
+ const { plan: plan2 } = await import("./plan-7M27X3OD.js");
3822
+ await plan2(freeform, {});
3806
3823
  } else {
3807
3824
  console.log(chalk6.yellow("Invalid choice. Please try again."));
3808
3825
  await showMainMenu();
@@ -3810,7 +3827,7 @@ async function showMainMenu() {
3810
3827
  }
3811
3828
  async function showReviewProgress(cwd) {
3812
3829
  try {
3813
- const { ReviewDatabase } = await import("./code-review-ODLXGXNZ.js");
3830
+ const { ReviewDatabase } = await import("./code-review-GJVBZPZA.js");
3814
3831
  const db = new ReviewDatabase(cwd);
3815
3832
  db.open();
3816
3833
  const stats = db.getStats();
@@ -3827,20 +3844,20 @@ async function showReviewProgress(cwd) {
3827
3844
  }
3828
3845
  }
3829
3846
  async function planTask() {
3830
- const { plan: plan2 } = await import("./plan-HCYXLSSD.js");
3847
+ const { plan: plan2 } = await import("./plan-7M27X3OD.js");
3831
3848
  const description = await promptWithCommands("Describe what you want to build", { allowMultiline: true });
3832
3849
  if (description.trim()) {
3833
3850
  await plan2(description, {});
3834
3851
  }
3835
3852
  }
3836
3853
  async function listAtoms() {
3837
- const { list: list2 } = await import("./list-REPLUXJF.js");
3854
+ const { list: list2 } = await import("./list-Q4HLHQJI.js");
3838
3855
  await list2({});
3839
3856
  }
3840
3857
  async function executeNext() {
3841
- const { listLocalAtoms: listLocalAtoms2 } = await import("./plan-HCYXLSSD.js");
3858
+ const { listLocalAtoms: listLocalAtoms2 } = await import("./plan-7M27X3OD.js");
3842
3859
  const { analyzeProject, getComplexityDescription, getModeDescription } = await import("./orchestration-HIF3KP25.js");
3843
- const { loadExecutionPreferences } = await import("./preferences-OAOZCZGR.js");
3860
+ const { loadExecutionPreferences } = await import("./preferences-SFXRVXT3.js");
3844
3861
  const cwd = process.cwd();
3845
3862
  const atoms = await listLocalAtoms2();
3846
3863
  const pendingAtoms = atoms.filter((a) => a.status === "READY" || a.status === "IN_PROGRESS");
@@ -3909,11 +3926,11 @@ async function executeNext() {
3909
3926
  }
3910
3927
  }
3911
3928
  if (selectedMode === "parallel-cloud") {
3912
- const { parallelExecuteCloud: parallelExecuteCloud2 } = await import("./parallel-23VQYK7H.js");
3929
+ const { parallelExecuteCloud: parallelExecuteCloud2 } = await import("./parallel-QLKYSZZ3.js");
3913
3930
  await parallelExecuteCloud2(runIds);
3914
3931
  return;
3915
3932
  }
3916
- const { parallelExecute } = await import("./parallel-23VQYK7H.js");
3933
+ const { parallelExecute } = await import("./parallel-QLKYSZZ3.js");
3917
3934
  await parallelExecute(runIds);
3918
3935
  return;
3919
3936
  }
@@ -3921,14 +3938,14 @@ async function executeNext() {
3921
3938
  const atomId = await prompt("Enter atom ID to execute (or press Enter for first pending)");
3922
3939
  const targetId = atomId.trim() || pendingAtoms[0]?.id;
3923
3940
  if (targetId) {
3924
- const { execute: execute2 } = await import("./execute-ZTJGSRBW.js");
3941
+ const { execute: execute2 } = await import("./execute-JAHXFYXL.js");
3925
3942
  await execute2(targetId, {});
3926
3943
  } else {
3927
3944
  console.log(chalk6.yellow("No atom to execute."));
3928
3945
  }
3929
3946
  }
3930
3947
  async function reportBug() {
3931
- const { bugReport: bugReport2 } = await import("./bug-IJCK43FK.js");
3948
+ const { bugReport: bugReport2 } = await import("./bug-NZHQ6QZF.js");
3932
3949
  const title = await prompt("Bug title");
3933
3950
  if (title.trim()) {
3934
3951
  await bugReport2(title, {});
@@ -3939,7 +3956,7 @@ async function viewStatus() {
3939
3956
  await status2();
3940
3957
  }
3941
3958
  async function settingsMenu() {
3942
- const { interactiveSettings } = await import("./preferences-OAOZCZGR.js");
3959
+ const { interactiveSettings } = await import("./preferences-SFXRVXT3.js");
3943
3960
  await interactiveSettings();
3944
3961
  await showMainMenu();
3945
3962
  }
@@ -3948,7 +3965,7 @@ async function reviewCode() {
3948
3965
  const reviewDbPath = join6(cwd, "docs", "code-review", "review-tasks.db");
3949
3966
  if (!existsSync6(reviewDbPath)) {
3950
3967
  console.log(chalk6.dim("Code review not initialized. Starting setup...\n"));
3951
- const { reviewInit: reviewInit2 } = await import("./review-F6DHAGDF.js");
3968
+ const { reviewInit: reviewInit2 } = await import("./review-BXESOS5R.js");
3952
3969
  await reviewInit2();
3953
3970
  console.log();
3954
3971
  }
@@ -3963,27 +3980,27 @@ async function reviewCode() {
3963
3980
  const choice = await prompt("Enter choice");
3964
3981
  switch (choice.toLowerCase()) {
3965
3982
  case "1": {
3966
- const { reviewAnalyze: reviewAnalyze2 } = await import("./review-F6DHAGDF.js");
3983
+ const { reviewAnalyze: reviewAnalyze2 } = await import("./review-BXESOS5R.js");
3967
3984
  await reviewAnalyze2();
3968
3985
  break;
3969
3986
  }
3970
3987
  case "2": {
3971
- const { reviewStatus: reviewStatus2 } = await import("./review-F6DHAGDF.js");
3988
+ const { reviewStatus: reviewStatus2 } = await import("./review-BXESOS5R.js");
3972
3989
  await reviewStatus2();
3973
3990
  break;
3974
3991
  }
3975
3992
  case "3": {
3976
- const { reviewNext: reviewNext2 } = await import("./review-F6DHAGDF.js");
3993
+ const { reviewNext: reviewNext2 } = await import("./review-BXESOS5R.js");
3977
3994
  await reviewNext2();
3978
3995
  break;
3979
3996
  }
3980
3997
  case "4": {
3981
- const { reviewList: reviewList2 } = await import("./review-F6DHAGDF.js");
3998
+ const { reviewList: reviewList2 } = await import("./review-BXESOS5R.js");
3982
3999
  await reviewList2({});
3983
4000
  break;
3984
4001
  }
3985
4002
  case "5": {
3986
- const { reviewRun: reviewRun2 } = await import("./review-F6DHAGDF.js");
4003
+ const { reviewRun: reviewRun2 } = await import("./review-BXESOS5R.js");
3987
4004
  await reviewRun2({ all: true });
3988
4005
  break;
3989
4006
  }
@@ -8243,6 +8260,9 @@ creditsCommand.command("audit").description("Show billing audit log (immutable r
8243
8260
  creditsCommand.action(async () => {
8244
8261
  await showCredits();
8245
8262
  });
8263
+ program.command("usage").description("Show usage by period and model").action(async () => {
8264
+ await showUsageDetails();
8265
+ });
8246
8266
  var preferencesCommand = program.command("preferences").description("Manage default model preferences");
8247
8267
  preferencesCommand.command("set <key> <model>").description("Set a model preference (fast-model, thinking-model, primary-adversarial, secondary-adversarial)").action(async (key, model) => {
8248
8268
  await setPreference(key, model);
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  list
3
- } from "./chunk-YA562WHL.js";
4
- import "./chunk-ACFMKTDL.js";
3
+ } from "./chunk-C4HVI2NJ.js";
4
+ import "./chunk-IKMCIWK3.js";
5
5
  import "./chunk-PCTP3LKJ.js";
6
6
  import "./chunk-PJRQI5UN.js";
7
7
  import "./chunk-EIEU3IIY.js";
@@ -6,9 +6,9 @@ import {
6
6
  parallelRunWaves,
7
7
  parallelSchedule,
8
8
  parallelStatus
9
- } from "./chunk-QTBRLNZQ.js";
9
+ } from "./chunk-3UOMLERV.js";
10
10
  import "./chunk-EBHHIUCB.js";
11
- import "./chunk-ACFMKTDL.js";
11
+ import "./chunk-IKMCIWK3.js";
12
12
  import "./chunk-PCTP3LKJ.js";
13
13
  import "./chunk-PJRQI5UN.js";
14
14
  import "./chunk-EIEU3IIY.js";
@@ -3,7 +3,7 @@ import {
3
3
  loadAtom,
4
4
  parseAtomDescription,
5
5
  plan
6
- } from "./chunk-ACFMKTDL.js";
6
+ } from "./chunk-IKMCIWK3.js";
7
7
  import "./chunk-PCTP3LKJ.js";
8
8
  import "./chunk-PJRQI5UN.js";
9
9
  import "./chunk-EIEU3IIY.js";
@@ -6,8 +6,10 @@ import {
6
6
  setExecutionPreference,
7
7
  setPreference,
8
8
  showExecutionPreferences,
9
- showPreferences
10
- } from "./chunk-CTWVQ6F3.js";
9
+ showPreferences,
10
+ showUsageDetails
11
+ } from "./chunk-K3XN7PN6.js";
12
+ import "./chunk-Q3GIFHIQ.js";
11
13
  import "./chunk-UFR2LX6G.js";
12
14
  import "./chunk-TFSHS7EN.js";
13
15
  import "./chunk-RDG5BUED.js";
@@ -24,5 +26,6 @@ export {
24
26
  setExecutionPreference,
25
27
  setPreference,
26
28
  showExecutionPreferences,
27
- showPreferences
29
+ showPreferences,
30
+ showUsageDetails
28
31
  };
@@ -9,8 +9,8 @@ import {
9
9
  reviewShow,
10
10
  reviewStatus,
11
11
  reviewUpdate
12
- } from "./chunk-M6GNIN64.js";
13
- import "./chunk-KG35EHZY.js";
12
+ } from "./chunk-6XLWTTGJ.js";
13
+ import "./chunk-YGDLWQBK.js";
14
14
  import "./chunk-EIEU3IIY.js";
15
15
  import "./chunk-UFR2LX6G.js";
16
16
  import "./chunk-4VNS5WPM.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "archondev",
3
- "version": "2.19.2",
3
+ "version": "2.19.4",
4
4
  "description": "Local-first AI-powered development governance system",
5
5
  "main": "dist/index.js",
6
6
  "bin": {