archondev 3.0.0 → 3.1.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 +27 -32
- package/dist/auth-ZMBA5HYH.js +13 -0
- package/dist/{bug-TFICZ4OP.js → bug-MOMNYU5J.js} +2 -2
- package/dist/{chunk-43IIEFB2.js → chunk-7ELR6RW6.js} +1 -1
- package/dist/{chunk-IG3H7C7R.js → chunk-ARHCVLQW.js} +4 -4
- package/dist/chunk-AWHINKO2.js +244 -0
- package/dist/{chunk-7RXZTPXY.js → chunk-BSG5XY3C.js} +6 -6
- package/dist/{chunk-AJNKSFHL.js → chunk-CI5E4EX3.js} +80 -5
- package/dist/{chunk-4TZOCXAI.js → chunk-ECEWULAA.js} +1 -1
- package/dist/chunk-EF66S6ZQ.js +1189 -0
- package/dist/chunk-EV5QU5KG.js +18 -0
- package/dist/{chunk-45T2VB5R.js → chunk-IZFUFXDN.js} +98 -237
- package/dist/{chunk-YK5Z6U5A.js → chunk-LE5EJ6I4.js} +23 -20
- package/dist/{chunk-PQS3TQB6.js → chunk-LSLQIPLQ.js} +6 -6
- package/dist/chunk-NQBS7L2F.js +55 -0
- package/dist/chunk-RAM67KA6.js +57 -0
- package/dist/{chunk-Q3GIFHIQ.js → client-PPPOHAVY.js} +4 -3
- package/dist/constants-BES4STNW.js +11 -0
- package/dist/{execute-HWUL2M3B.js → execute-WSCLLLY6.js} +4 -4
- package/dist/geo-IRUGSLZS.js +50 -0
- package/dist/index.js +760 -1239
- package/dist/{interviewer-ZGKR7YQQ.js → interviewer-ZUYQ5ZFJ.js} +2 -2
- package/dist/{keys-3PRAVIRC.js → keys-SQUTA4L2.js} +2 -2
- package/dist/{list-7IBMJCCF.js → list-HZM7DNVS.js} +4 -4
- package/dist/{parallel-4PXJA2QD.js → parallel-MWPBKEEN.js} +5 -6
- package/dist/{plan-HBAUG3KD.js → plan-3Z6M4LE6.js} +3 -3
- package/dist/{preferences-VVFGRNPD.js → preferences-OXVXWARL.js} +2 -2
- package/dist/{ship-KHL6NVC2.js → ship-CTZU6RYR.js} +1 -1
- package/dist/{chunk-ONH6Y3CS.js → tier-selection-5KPN2RF2.js} +7 -28
- package/dist/truth-layer-7N32HKCE.js +19 -0
- package/package.json +2 -2
- package/dist/auth-T4C7OQWO.js +0 -14
- package/dist/chunk-57NSGWWD.js +0 -270
- package/dist/chunk-CFJECC3B.js +0 -495
- package/dist/chunk-GGRW4NTA.js +0 -118
- package/dist/chunk-M4LGRTLC.js +0 -10
- package/dist/client-PHW2C2HB.js +0 -11
- package/dist/constants-XDIWFFPN.js +0 -11
- package/dist/geo-BWH5PUBK.js +0 -20
- package/dist/tier-selection-O5AFLKD6.js +0 -18
package/dist/index.js
CHANGED
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
resetPreferences,
|
|
4
|
+
setExecutionPreference,
|
|
5
|
+
setPreference,
|
|
6
|
+
showExecutionPreferences,
|
|
7
|
+
showPreferences,
|
|
8
|
+
showUsageDetails
|
|
9
|
+
} from "./chunk-LSLQIPLQ.js";
|
|
10
|
+
import {
|
|
11
|
+
a11yBadge,
|
|
12
|
+
a11yCheck,
|
|
13
|
+
a11yFix,
|
|
14
|
+
a11yPreDeploy
|
|
15
|
+
} from "./chunk-FWLLGLD5.js";
|
|
2
16
|
import {
|
|
3
17
|
createSeoCommand
|
|
4
18
|
} from "./chunk-JF7JCK6H.js";
|
|
5
|
-
import {
|
|
6
|
-
createGeoCommand
|
|
7
|
-
} from "./chunk-CFJECC3B.js";
|
|
8
19
|
import {
|
|
9
20
|
reviewAnalyze,
|
|
10
21
|
reviewExport,
|
|
@@ -19,23 +30,18 @@ import {
|
|
|
19
30
|
} from "./chunk-RR5RLVGV.js";
|
|
20
31
|
import "./chunk-UDR6XLVQ.js";
|
|
21
32
|
import {
|
|
22
|
-
|
|
23
|
-
} from "./chunk-
|
|
24
|
-
import {
|
|
25
|
-
resetPreferences,
|
|
26
|
-
setExecutionPreference,
|
|
27
|
-
setPreference,
|
|
28
|
-
showExecutionPreferences,
|
|
29
|
-
showPreferences,
|
|
30
|
-
showUsageDetails
|
|
31
|
-
} from "./chunk-PQS3TQB6.js";
|
|
33
|
+
createTruthLayerCommand
|
|
34
|
+
} from "./chunk-AWHINKO2.js";
|
|
32
35
|
import {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
} from "./chunk-
|
|
36
|
+
BANNED_WORDS_AI_WASHING,
|
|
37
|
+
BANNED_WORDS_GENERIC,
|
|
38
|
+
createGeoCommand,
|
|
39
|
+
findBannedWords
|
|
40
|
+
} from "./chunk-EF66S6ZQ.js";
|
|
38
41
|
import "./chunk-3ASILTFB.js";
|
|
42
|
+
import {
|
|
43
|
+
ship
|
|
44
|
+
} from "./chunk-CI5E4EX3.js";
|
|
39
45
|
import {
|
|
40
46
|
buildDependencyGraph,
|
|
41
47
|
cloudCancel,
|
|
@@ -48,10 +54,7 @@ import {
|
|
|
48
54
|
parallelSchedule,
|
|
49
55
|
parallelStatus,
|
|
50
56
|
scheduleExecution
|
|
51
|
-
} from "./chunk-
|
|
52
|
-
import {
|
|
53
|
-
createAuthedSupabaseClient
|
|
54
|
-
} from "./chunk-Q3GIFHIQ.js";
|
|
57
|
+
} from "./chunk-IZFUFXDN.js";
|
|
55
58
|
import {
|
|
56
59
|
DependencyParser,
|
|
57
60
|
EnvironmentConfigLoader,
|
|
@@ -61,71 +64,69 @@ import {
|
|
|
61
64
|
setPolicy,
|
|
62
65
|
showPolicy,
|
|
63
66
|
suggestSkills
|
|
64
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-LE5EJ6I4.js";
|
|
65
68
|
import {
|
|
66
69
|
list
|
|
67
|
-
} from "./chunk-
|
|
70
|
+
} from "./chunk-7ELR6RW6.js";
|
|
71
|
+
import {
|
|
72
|
+
bugReport
|
|
73
|
+
} from "./chunk-ECEWULAA.js";
|
|
74
|
+
import {
|
|
75
|
+
addKey,
|
|
76
|
+
listKeys,
|
|
77
|
+
removeKey,
|
|
78
|
+
setPrimaryKey
|
|
79
|
+
} from "./chunk-ARHCVLQW.js";
|
|
80
|
+
import {
|
|
81
|
+
login,
|
|
82
|
+
logout,
|
|
83
|
+
status
|
|
84
|
+
} from "./chunk-RAM67KA6.js";
|
|
85
|
+
import {
|
|
86
|
+
printRetiredRemotePath
|
|
87
|
+
} from "./chunk-EV5QU5KG.js";
|
|
88
|
+
import {
|
|
89
|
+
init,
|
|
90
|
+
isInitialized
|
|
91
|
+
} from "./chunk-P666JE3G.js";
|
|
68
92
|
import {
|
|
69
93
|
listLocalAtoms,
|
|
70
94
|
loadAtom,
|
|
71
95
|
plan
|
|
72
|
-
} from "./chunk-
|
|
96
|
+
} from "./chunk-BSG5XY3C.js";
|
|
73
97
|
import {
|
|
74
98
|
debugLog,
|
|
75
99
|
getDebugLogPath,
|
|
76
100
|
summarizeLocalUsage
|
|
77
101
|
} from "./chunk-I3BBA7MB.js";
|
|
78
|
-
import {
|
|
79
|
-
ArchitectureParser
|
|
80
|
-
} from "./chunk-5EVHUDQX.js";
|
|
81
|
-
import {
|
|
82
|
-
bugReport
|
|
83
|
-
} from "./chunk-4TZOCXAI.js";
|
|
84
102
|
import "./chunk-IYZN6FPJ.js";
|
|
85
|
-
import
|
|
103
|
+
import {
|
|
104
|
+
ArchitectAgent
|
|
105
|
+
} from "./chunk-D3TVDCJA.js";
|
|
86
106
|
import {
|
|
87
107
|
err,
|
|
88
108
|
ok,
|
|
89
109
|
sleep
|
|
90
110
|
} from "./chunk-NIIFUBOE.js";
|
|
111
|
+
import {
|
|
112
|
+
loadConfig,
|
|
113
|
+
saveConfig
|
|
114
|
+
} from "./chunk-NQBS7L2F.js";
|
|
115
|
+
import {
|
|
116
|
+
ArchitectureParser
|
|
117
|
+
} from "./chunk-5EVHUDQX.js";
|
|
91
118
|
import {
|
|
92
119
|
findModel
|
|
93
120
|
} from "./chunk-7C6JELBL.js";
|
|
94
|
-
import {
|
|
95
|
-
addKey,
|
|
96
|
-
listKeys,
|
|
97
|
-
removeKey,
|
|
98
|
-
setPrimaryKey
|
|
99
|
-
} from "./chunk-IG3H7C7R.js";
|
|
100
121
|
import "./chunk-TFSHS7EN.js";
|
|
101
122
|
import "./chunk-RDG5BUED.js";
|
|
102
|
-
import {
|
|
103
|
-
login,
|
|
104
|
-
logout,
|
|
105
|
-
status
|
|
106
|
-
} from "./chunk-57NSGWWD.js";
|
|
107
|
-
import {
|
|
108
|
-
API_URL,
|
|
109
|
-
SUPABASE_ANON_KEY,
|
|
110
|
-
SUPABASE_URL
|
|
111
|
-
} from "./chunk-M4LGRTLC.js";
|
|
112
|
-
import "./chunk-ONH6Y3CS.js";
|
|
113
|
-
import {
|
|
114
|
-
getAuthToken,
|
|
115
|
-
loadConfig,
|
|
116
|
-
saveConfig
|
|
117
|
-
} from "./chunk-GGRW4NTA.js";
|
|
118
|
-
import {
|
|
119
|
-
init,
|
|
120
|
-
isInitialized
|
|
121
|
-
} from "./chunk-P666JE3G.js";
|
|
122
123
|
import {
|
|
123
124
|
__require
|
|
124
125
|
} from "./chunk-4VNS5WPM.js";
|
|
125
126
|
|
|
126
127
|
// src/cli/index.ts
|
|
127
|
-
import { Command as
|
|
128
|
-
import
|
|
128
|
+
import { Command as Command4, Option } from "commander";
|
|
129
|
+
import chalk18 from "chalk";
|
|
129
130
|
import "dotenv/config";
|
|
130
131
|
|
|
131
132
|
// src/cli/terminal-compat.ts
|
|
@@ -946,38 +947,48 @@ import { fileURLToPath } from "url";
|
|
|
946
947
|
import { execSync as execSync2 } from "child_process";
|
|
947
948
|
var __dirname = dirname3(fileURLToPath(import.meta.url));
|
|
948
949
|
var UPDATE_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
949
|
-
function getCurrentVersion() {
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
950
|
+
function getCurrentVersion(options) {
|
|
951
|
+
const moduleDir = options?.moduleDir ?? __dirname;
|
|
952
|
+
const entrypointPath = options?.entrypointPath ?? process.argv[1];
|
|
953
|
+
const candidatePackagePaths = [
|
|
954
|
+
...entrypointPath ? [
|
|
955
|
+
join4(dirname3(entrypointPath), "package.json"),
|
|
956
|
+
join4(dirname3(entrypointPath), "..", "package.json"),
|
|
957
|
+
join4(dirname3(entrypointPath), "..", "..", "package.json")
|
|
958
|
+
] : [],
|
|
959
|
+
join4(moduleDir, "package.json"),
|
|
960
|
+
join4(moduleDir, "..", "package.json"),
|
|
961
|
+
join4(moduleDir, "..", "..", "package.json"),
|
|
962
|
+
join4(moduleDir, "..", "..", "..", "package.json")
|
|
963
|
+
];
|
|
964
|
+
for (const pkgPath of candidatePackagePaths) {
|
|
965
|
+
try {
|
|
966
|
+
if (!existsSync4(pkgPath)) continue;
|
|
967
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
968
|
+
if (pkg.name === "archondev" && pkg.version) {
|
|
969
|
+
return pkg.version;
|
|
970
|
+
}
|
|
971
|
+
} catch {
|
|
972
|
+
continue;
|
|
959
973
|
}
|
|
960
|
-
} catch {
|
|
961
974
|
}
|
|
975
|
+
const globalVersionLookup = options?.globalVersionLookup ?? (() => {
|
|
976
|
+
try {
|
|
977
|
+
const result = execSync2("npm list -g archondev --depth=0 --json 2>/dev/null", {
|
|
978
|
+
encoding: "utf-8",
|
|
979
|
+
timeout: 3e3,
|
|
980
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
981
|
+
});
|
|
982
|
+
const data = JSON.parse(result);
|
|
983
|
+
return data.dependencies?.archondev?.version ?? null;
|
|
984
|
+
} catch {
|
|
985
|
+
return null;
|
|
986
|
+
}
|
|
987
|
+
});
|
|
962
988
|
try {
|
|
963
|
-
const
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
join4(__dirname, "..", "package.json"),
|
|
967
|
-
// From dist/cli/ or src/cli/
|
|
968
|
-
join4(__dirname, "..", "..", "package.json"),
|
|
969
|
-
join4(__dirname, "..", "..", "..", "package.json")
|
|
970
|
-
];
|
|
971
|
-
for (const pkgPath of paths) {
|
|
972
|
-
try {
|
|
973
|
-
if (!existsSync4(pkgPath)) continue;
|
|
974
|
-
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
975
|
-
if (pkg.name === "archondev" && pkg.version) {
|
|
976
|
-
return pkg.version;
|
|
977
|
-
}
|
|
978
|
-
} catch {
|
|
979
|
-
continue;
|
|
980
|
-
}
|
|
989
|
+
const globalVersion = globalVersionLookup();
|
|
990
|
+
if (globalVersion) {
|
|
991
|
+
return globalVersion;
|
|
981
992
|
}
|
|
982
993
|
} catch {
|
|
983
994
|
}
|
|
@@ -2929,8 +2940,12 @@ var GovernanceStore = class {
|
|
|
2929
2940
|
if (index === -1) {
|
|
2930
2941
|
return err(`Task not found: ${taskId}`);
|
|
2931
2942
|
}
|
|
2943
|
+
const existingTask = tasks.value[index];
|
|
2944
|
+
if (!existingTask) {
|
|
2945
|
+
return err(`Task not found: ${taskId}`);
|
|
2946
|
+
}
|
|
2932
2947
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2933
|
-
const task = { ...
|
|
2948
|
+
const task = { ...existingTask };
|
|
2934
2949
|
task.status = status2;
|
|
2935
2950
|
task.notes = notes ?? task.notes;
|
|
2936
2951
|
task.updated_at = now;
|
|
@@ -3646,7 +3661,7 @@ async function runExploreFlow(cwd, followUpInput, options = {}) {
|
|
|
3646
3661
|
case "1": {
|
|
3647
3662
|
const description = await promptWithCommands("Describe what you want to do", { allowMultiline: true });
|
|
3648
3663
|
if (description.trim()) {
|
|
3649
|
-
const { plan: plan2 } = await import("./plan-
|
|
3664
|
+
const { plan: plan2 } = await import("./plan-3Z6M4LE6.js");
|
|
3650
3665
|
await plan2(description, { conversational: true, conciseOutput: true });
|
|
3651
3666
|
}
|
|
3652
3667
|
await showMainMenu();
|
|
@@ -3776,7 +3791,7 @@ async function gatherProjectInfo(cwd) {
|
|
|
3776
3791
|
return info;
|
|
3777
3792
|
}
|
|
3778
3793
|
async function runConversationalInterview(cwd, initialMessage) {
|
|
3779
|
-
const { InterviewerAgent, createInterviewerAgent } = await import("./interviewer-
|
|
3794
|
+
const { InterviewerAgent, createInterviewerAgent } = await import("./interviewer-ZUYQ5ZFJ.js");
|
|
3780
3795
|
const agent = await createInterviewerAgent();
|
|
3781
3796
|
if (agent && agent.isAvailable()) {
|
|
3782
3797
|
await runAIInterview(cwd, initialMessage, agent);
|
|
@@ -3897,7 +3912,7 @@ ${state.forbiddenPatterns?.length ? `- **Forbidden patterns:** ${state.forbidden
|
|
|
3897
3912
|
const hintedTask = initialTaskHint?.trim() ?? "";
|
|
3898
3913
|
if (hintedTask) {
|
|
3899
3914
|
console.log(chalk6.dim("Using your request above as the first task.\n"));
|
|
3900
|
-
const { plan: plan2 } = await import("./plan-
|
|
3915
|
+
const { plan: plan2 } = await import("./plan-3Z6M4LE6.js");
|
|
3901
3916
|
await plan2(hintedTask, { conversational: true, conciseOutput: true });
|
|
3902
3917
|
return;
|
|
3903
3918
|
}
|
|
@@ -3922,7 +3937,7 @@ ${state.forbiddenPatterns?.length ? `- **Forbidden patterns:** ${state.forbidden
|
|
|
3922
3937
|
description = continueAnswer.trim();
|
|
3923
3938
|
}
|
|
3924
3939
|
if (description.trim()) {
|
|
3925
|
-
const { plan: plan2 } = await import("./plan-
|
|
3940
|
+
const { plan: plan2 } = await import("./plan-3Z6M4LE6.js");
|
|
3926
3941
|
await plan2(description, { conversational: true, conciseOutput: true });
|
|
3927
3942
|
}
|
|
3928
3943
|
}
|
|
@@ -4148,7 +4163,7 @@ async function handleAgentConversationInput(cwd, input, state) {
|
|
|
4148
4163
|
await continueWithCurrentTask(cwd, { runAllReady: true });
|
|
4149
4164
|
return true;
|
|
4150
4165
|
case "ship": {
|
|
4151
|
-
const { ship: shipCommand } = await import("./ship-
|
|
4166
|
+
const { ship: shipCommand } = await import("./ship-CTZU6RYR.js");
|
|
4152
4167
|
await shipCommand();
|
|
4153
4168
|
return true;
|
|
4154
4169
|
}
|
|
@@ -4158,7 +4173,7 @@ async function handleAgentConversationInput(cwd, input, state) {
|
|
|
4158
4173
|
case "reference_previous_request": {
|
|
4159
4174
|
const hasPlan = await showLatestPlannedAtom(cwd);
|
|
4160
4175
|
if (!hasPlan && lastDetailedRequest) {
|
|
4161
|
-
const { plan: plan2 } = await import("./plan-
|
|
4176
|
+
const { plan: plan2 } = await import("./plan-3Z6M4LE6.js");
|
|
4162
4177
|
await plan2(await withAllowedPathScope(cwd, lastDetailedRequest), { conversational: true, conciseOutput: true });
|
|
4163
4178
|
conversationStage = "plan_ready";
|
|
4164
4179
|
await showLatestPlannedAtom(cwd);
|
|
@@ -4192,7 +4207,7 @@ async function handleAgentConversationInput(cwd, input, state) {
|
|
|
4192
4207
|
return true;
|
|
4193
4208
|
case "plan":
|
|
4194
4209
|
default: {
|
|
4195
|
-
const { plan: plan2 } = await import("./plan-
|
|
4210
|
+
const { plan: plan2 } = await import("./plan-3Z6M4LE6.js");
|
|
4196
4211
|
await plan2(await withAllowedPathScope(cwd, input), { conversational: true, conciseOutput: true });
|
|
4197
4212
|
conversationStage = "plan_ready";
|
|
4198
4213
|
if (shouldAutoExecuteAfterPlanning(input) || shouldImplicitlyExecuteAfterPlanning(input)) {
|
|
@@ -4361,7 +4376,7 @@ async function showProposalForApproval(input) {
|
|
|
4361
4376
|
}
|
|
4362
4377
|
}
|
|
4363
4378
|
async function showLatestPlannedAtom(cwd) {
|
|
4364
|
-
const { listLocalAtoms: listLocalAtoms2 } = await import("./plan-
|
|
4379
|
+
const { listLocalAtoms: listLocalAtoms2 } = await import("./plan-3Z6M4LE6.js");
|
|
4365
4380
|
const atoms = await listLocalAtoms2();
|
|
4366
4381
|
if (atoms.length === 0) {
|
|
4367
4382
|
console.log(chalk6.yellow("No tasks found yet. Tell me what to plan."));
|
|
@@ -4528,7 +4543,7 @@ async function applyApprovedProposal(cwd) {
|
|
|
4528
4543
|
});
|
|
4529
4544
|
}
|
|
4530
4545
|
async function createTaskFromRequest(cwd, request) {
|
|
4531
|
-
const { plan: plan2, listLocalAtoms: listLocalAtoms2 } = await import("./plan-
|
|
4546
|
+
const { plan: plan2, listLocalAtoms: listLocalAtoms2 } = await import("./plan-3Z6M4LE6.js");
|
|
4532
4547
|
const before = await listLocalAtoms2();
|
|
4533
4548
|
const beforeIds = new Set(before.map((atom) => atom.externalId));
|
|
4534
4549
|
await plan2(await withAllowedPathScope(cwd, request), { conversational: true, conciseOutput: true });
|
|
@@ -4714,13 +4729,13 @@ async function continueWithCurrentTask(cwd, options = {}) {
|
|
|
4714
4729
|
return;
|
|
4715
4730
|
}
|
|
4716
4731
|
continueExecutionInFlight = true;
|
|
4717
|
-
const { listLocalAtoms: listLocalAtoms2 } = await import("./plan-
|
|
4732
|
+
const { listLocalAtoms: listLocalAtoms2 } = await import("./plan-3Z6M4LE6.js");
|
|
4718
4733
|
const byMostRecent2 = (a, b) => {
|
|
4719
4734
|
const aTime = new Date(String(a.updatedAt ?? a.createdAt ?? "")).getTime() || 0;
|
|
4720
4735
|
const bTime = new Date(String(b.updatedAt ?? b.createdAt ?? "")).getTime() || 0;
|
|
4721
4736
|
return bTime - aTime;
|
|
4722
4737
|
};
|
|
4723
|
-
const { execute: execute2 } = await import("./execute-
|
|
4738
|
+
const { execute: execute2 } = await import("./execute-WSCLLLY6.js");
|
|
4724
4739
|
const runAllReady = options.runAllReady === true;
|
|
4725
4740
|
const scopeIds = options.onlyAtomIds ? new Set(options.onlyAtomIds) : null;
|
|
4726
4741
|
const attempted = /* @__PURE__ */ new Set();
|
|
@@ -4775,7 +4790,7 @@ async function continueWithCurrentTask(cwd, options = {}) {
|
|
|
4775
4790
|
return;
|
|
4776
4791
|
}
|
|
4777
4792
|
if (continuationDecision.mode === "parallel") {
|
|
4778
|
-
const { parallelRunWaves: parallelRunWaves2 } = await import("./parallel-
|
|
4793
|
+
const { parallelRunWaves: parallelRunWaves2 } = await import("./parallel-MWPBKEEN.js");
|
|
4779
4794
|
queueStarted = true;
|
|
4780
4795
|
conversationStage = "executing";
|
|
4781
4796
|
console.log(chalk6.dim(`
|
|
@@ -4842,7 +4857,7 @@ Context note: session memory is around ${usagePercent}%. I will prepare a handof
|
|
|
4842
4857
|
}
|
|
4843
4858
|
}
|
|
4844
4859
|
async function performSessionHandoff(cwd, contextManager) {
|
|
4845
|
-
const { listLocalAtoms: listLocalAtoms2 } = await import("./plan-
|
|
4860
|
+
const { listLocalAtoms: listLocalAtoms2 } = await import("./plan-3Z6M4LE6.js");
|
|
4846
4861
|
const atoms = await listLocalAtoms2();
|
|
4847
4862
|
const pendingAtomIds = atoms.filter((atom) => atom.status === "READY" || atom.status === "IN_PROGRESS" || atom.status === "BLOCKED").map((atom) => atom.externalId);
|
|
4848
4863
|
await contextManager.savePendingAtoms(pendingAtomIds, cwd);
|
|
@@ -4875,7 +4890,7 @@ async function performSessionHandoff(cwd, contextManager) {
|
|
|
4875
4890
|
console.log(chalk6.yellow("\nContext note: I wrote a handoff, saved pending work, and compacted the local session state so we can keep going without losing continuity.\n"));
|
|
4876
4891
|
}
|
|
4877
4892
|
async function replanLatestBlockedAtom(cwd) {
|
|
4878
|
-
const { listLocalAtoms: listLocalAtoms2, plan: plan2 } = await import("./plan-
|
|
4893
|
+
const { listLocalAtoms: listLocalAtoms2, plan: plan2 } = await import("./plan-3Z6M4LE6.js");
|
|
4879
4894
|
const atoms = await listLocalAtoms2();
|
|
4880
4895
|
const blocked = atoms.filter((a) => a.status === "BLOCKED" && (a.errorMessage ?? "").toLowerCase().includes("outside the allowed paths")).sort((a, b) => {
|
|
4881
4896
|
const aTime = new Date(String(a.updatedAt ?? a.createdAt ?? "")).getTime() || 0;
|
|
@@ -4934,7 +4949,7 @@ async function showMainMenu() {
|
|
|
4934
4949
|
} }] : [],
|
|
4935
4950
|
{ key: "7", label: "Settings & Preferences", action: () => settingsMenu() },
|
|
4936
4951
|
{ key: "8", label: "Upgrade tier", action: async () => {
|
|
4937
|
-
const { showUpgradeMenu } = await import("./tier-selection-
|
|
4952
|
+
const { showUpgradeMenu } = await import("./tier-selection-5KPN2RF2.js");
|
|
4938
4953
|
await showUpgradeMenu();
|
|
4939
4954
|
} },
|
|
4940
4955
|
{ key: "q", label: "Quit", action: async () => process.exit(0) }
|
|
@@ -4989,7 +5004,7 @@ async function handleFreeformJourneyInput(cwd, input) {
|
|
|
4989
5004
|
const state = detectProjectState(cwd);
|
|
4990
5005
|
if (state.hasArchitecture) {
|
|
4991
5006
|
console.log(chalk6.dim("\n> Got it! Creating a task for this...\n"));
|
|
4992
|
-
const { plan: plan3 } = await import("./plan-
|
|
5007
|
+
const { plan: plan3 } = await import("./plan-3Z6M4LE6.js");
|
|
4993
5008
|
await plan3(await withAllowedPathScope(cwd, freeform), { conversational: true, conciseOutput: true });
|
|
4994
5009
|
return true;
|
|
4995
5010
|
}
|
|
@@ -4998,7 +5013,7 @@ async function handleFreeformJourneyInput(cwd, input) {
|
|
|
4998
5013
|
return true;
|
|
4999
5014
|
}
|
|
5000
5015
|
console.log(chalk6.dim("\n> Got it! Creating a task for this...\n"));
|
|
5001
|
-
const { plan: plan2 } = await import("./plan-
|
|
5016
|
+
const { plan: plan2 } = await import("./plan-3Z6M4LE6.js");
|
|
5002
5017
|
await plan2(await withAllowedPathScope(cwd, freeform), { conversational: true, conciseOutput: true });
|
|
5003
5018
|
return true;
|
|
5004
5019
|
}
|
|
@@ -5047,7 +5062,7 @@ function isFileLocationQuestion(input) {
|
|
|
5047
5062
|
return true;
|
|
5048
5063
|
}
|
|
5049
5064
|
async function answerLatestOutputLocation(cwd) {
|
|
5050
|
-
const { listLocalAtoms: listLocalAtoms2 } = await import("./plan-
|
|
5065
|
+
const { listLocalAtoms: listLocalAtoms2 } = await import("./plan-3Z6M4LE6.js");
|
|
5051
5066
|
const atoms = await listLocalAtoms2();
|
|
5052
5067
|
const latestDone = atoms.filter((atom) => atom.status === "DONE").sort((a, b) => {
|
|
5053
5068
|
const aTime = new Date(String(a.updatedAt ?? a.createdAt ?? "")).getTime() || 0;
|
|
@@ -5096,7 +5111,7 @@ async function handlePostExploreAction(cwd, request, options = {}) {
|
|
|
5096
5111
|
} else {
|
|
5097
5112
|
console.log(chalk6.dim("> Got it! Creating a task for this...\n"));
|
|
5098
5113
|
}
|
|
5099
|
-
const { plan: plan2 } = await import("./plan-
|
|
5114
|
+
const { plan: plan2 } = await import("./plan-3Z6M4LE6.js");
|
|
5100
5115
|
await plan2(await withAllowedPathScope(cwd, request), { conversational: true, conciseOutput: true });
|
|
5101
5116
|
if (options.agentMode) {
|
|
5102
5117
|
if (shouldAutoExecuteAfterPlanning(sourceInput) || shouldImplicitlyExecuteAfterPlanning(sourceInput)) {
|
|
@@ -5119,20 +5134,20 @@ Constraints:
|
|
|
5119
5134
|
- If required files are outside this scope, propose the minimum architecture path update first.`;
|
|
5120
5135
|
}
|
|
5121
5136
|
async function planTask() {
|
|
5122
|
-
const { plan: plan2 } = await import("./plan-
|
|
5137
|
+
const { plan: plan2 } = await import("./plan-3Z6M4LE6.js");
|
|
5123
5138
|
const description = await promptWithCommands("Describe what you want to build", { allowMultiline: true });
|
|
5124
5139
|
if (description.trim()) {
|
|
5125
5140
|
await plan2(description, { conversational: true, conciseOutput: true });
|
|
5126
5141
|
}
|
|
5127
5142
|
}
|
|
5128
5143
|
async function listAtoms() {
|
|
5129
|
-
const { list: list2 } = await import("./list-
|
|
5144
|
+
const { list: list2 } = await import("./list-HZM7DNVS.js");
|
|
5130
5145
|
await list2({});
|
|
5131
5146
|
}
|
|
5132
5147
|
async function executeNext() {
|
|
5133
|
-
const { listLocalAtoms: listLocalAtoms2 } = await import("./plan-
|
|
5148
|
+
const { listLocalAtoms: listLocalAtoms2 } = await import("./plan-3Z6M4LE6.js");
|
|
5134
5149
|
const { analyzeProject, getComplexityDescription, getModeDescription } = await import("./orchestration-HIF3KP25.js");
|
|
5135
|
-
const { loadExecutionPreferences } = await import("./preferences-
|
|
5150
|
+
const { loadExecutionPreferences } = await import("./preferences-OXVXWARL.js");
|
|
5136
5151
|
const cwd = process.cwd();
|
|
5137
5152
|
const atoms = await listLocalAtoms2();
|
|
5138
5153
|
const pendingAtoms = atoms.filter((a) => a.status === "READY" || a.status === "IN_PROGRESS");
|
|
@@ -5192,7 +5207,7 @@ async function executeNext() {
|
|
|
5192
5207
|
console.log(chalk6.dim(`Running first ${runIds.length} tasks.`));
|
|
5193
5208
|
}
|
|
5194
5209
|
}
|
|
5195
|
-
const { parallelExecute } = await import("./parallel-
|
|
5210
|
+
const { parallelExecute } = await import("./parallel-MWPBKEEN.js");
|
|
5196
5211
|
await parallelExecute(runIds);
|
|
5197
5212
|
return;
|
|
5198
5213
|
}
|
|
@@ -5200,25 +5215,25 @@ async function executeNext() {
|
|
|
5200
5215
|
const atomId = await prompt("Enter task ID to execute (or press Enter for first pending)");
|
|
5201
5216
|
const targetId = atomId.trim() || pendingAtoms[0]?.id;
|
|
5202
5217
|
if (targetId) {
|
|
5203
|
-
const { execute: execute2 } = await import("./execute-
|
|
5218
|
+
const { execute: execute2 } = await import("./execute-WSCLLLY6.js");
|
|
5204
5219
|
await execute2(targetId, {});
|
|
5205
5220
|
} else {
|
|
5206
5221
|
console.log(chalk6.yellow("No task to execute."));
|
|
5207
5222
|
}
|
|
5208
5223
|
}
|
|
5209
5224
|
async function reportBug() {
|
|
5210
|
-
const { bugReport: bugReport2 } = await import("./bug-
|
|
5225
|
+
const { bugReport: bugReport2 } = await import("./bug-MOMNYU5J.js");
|
|
5211
5226
|
const title = await prompt("Bug title");
|
|
5212
5227
|
if (title.trim()) {
|
|
5213
5228
|
await bugReport2(title, {});
|
|
5214
5229
|
}
|
|
5215
5230
|
}
|
|
5216
5231
|
async function viewStatus() {
|
|
5217
|
-
const { status: status2 } = await import("./auth-
|
|
5232
|
+
const { status: status2 } = await import("./auth-ZMBA5HYH.js");
|
|
5218
5233
|
await status2();
|
|
5219
5234
|
}
|
|
5220
5235
|
async function settingsMenu() {
|
|
5221
|
-
const { interactiveSettings } = await import("./preferences-
|
|
5236
|
+
const { interactiveSettings } = await import("./preferences-OXVXWARL.js");
|
|
5222
5237
|
await interactiveSettings();
|
|
5223
5238
|
}
|
|
5224
5239
|
async function reviewCode() {
|
|
@@ -5293,12 +5308,12 @@ async function handleInSessionCommand(input) {
|
|
|
5293
5308
|
}
|
|
5294
5309
|
}
|
|
5295
5310
|
if (normalized === "mode" || normalized === "archon mode" || normalized === "upgrade" || normalized === "archon upgrade" || normalized === "pricing" || normalized === "archon pricing") {
|
|
5296
|
-
const { showUpgradeMenu } = await import("./tier-selection-
|
|
5311
|
+
const { showUpgradeMenu } = await import("./tier-selection-5KPN2RF2.js");
|
|
5297
5312
|
await showUpgradeMenu();
|
|
5298
5313
|
return true;
|
|
5299
5314
|
}
|
|
5300
5315
|
if (normalized === "status" || normalized === "archon status") {
|
|
5301
|
-
const { status: status2 } = await import("./auth-
|
|
5316
|
+
const { status: status2 } = await import("./auth-ZMBA5HYH.js");
|
|
5302
5317
|
await status2();
|
|
5303
5318
|
return true;
|
|
5304
5319
|
}
|
|
@@ -5315,7 +5330,7 @@ async function handleInSessionCommand(input) {
|
|
|
5315
5330
|
return true;
|
|
5316
5331
|
}
|
|
5317
5332
|
if (normalized === "keys" || normalized === "archon keys") {
|
|
5318
|
-
const { listKeys: listKeys2 } = await import("./keys-
|
|
5333
|
+
const { listKeys: listKeys2 } = await import("./keys-SQUTA4L2.js");
|
|
5319
5334
|
await listKeys2();
|
|
5320
5335
|
return true;
|
|
5321
5336
|
}
|
|
@@ -5349,7 +5364,7 @@ async function handleSlashCommand(input) {
|
|
|
5349
5364
|
const arg = parts.slice(1).join(" ").trim();
|
|
5350
5365
|
switch (command) {
|
|
5351
5366
|
case "/plan": {
|
|
5352
|
-
const { plan: plan2 } = await import("./plan-
|
|
5367
|
+
const { plan: plan2 } = await import("./plan-3Z6M4LE6.js");
|
|
5353
5368
|
if (arg) {
|
|
5354
5369
|
await plan2(arg, { conversational: true, conciseOutput: true });
|
|
5355
5370
|
} else {
|
|
@@ -5376,7 +5391,7 @@ async function handleSlashCommand(input) {
|
|
|
5376
5391
|
await settingsMenu();
|
|
5377
5392
|
return true;
|
|
5378
5393
|
case "/upgrade": {
|
|
5379
|
-
const { showUpgradeMenu } = await import("./tier-selection-
|
|
5394
|
+
const { showUpgradeMenu } = await import("./tier-selection-5KPN2RF2.js");
|
|
5380
5395
|
await showUpgradeMenu();
|
|
5381
5396
|
return true;
|
|
5382
5397
|
}
|
|
@@ -5457,7 +5472,7 @@ async function promptWithCommands(question, options = {}) {
|
|
|
5457
5472
|
async function runWebChecksSuite() {
|
|
5458
5473
|
const { a11yCheck: a11yCheck2 } = await import("./a11y-O35BAA25.js");
|
|
5459
5474
|
const { seoCheck } = await import("./seo-PMI42KRZ.js");
|
|
5460
|
-
const { geoAudit } = await import("./geo-
|
|
5475
|
+
const { geoAudit } = await import("./geo-IRUGSLZS.js");
|
|
5461
5476
|
console.log(chalk6.blue("\nRunning web checks (A11y, SEO, GEO)...\n"));
|
|
5462
5477
|
await a11yCheck2({});
|
|
5463
5478
|
await seoCheck({});
|
|
@@ -5498,17 +5513,17 @@ async function showWebChecksMenu() {
|
|
|
5498
5513
|
break;
|
|
5499
5514
|
}
|
|
5500
5515
|
case "4": {
|
|
5501
|
-
const { geoAudit } = await import("./geo-
|
|
5516
|
+
const { geoAudit } = await import("./geo-IRUGSLZS.js");
|
|
5502
5517
|
await geoAudit();
|
|
5503
5518
|
break;
|
|
5504
5519
|
}
|
|
5505
5520
|
case "5": {
|
|
5506
|
-
const { geoIdentity } = await import("./geo-
|
|
5521
|
+
const { geoIdentity } = await import("./geo-IRUGSLZS.js");
|
|
5507
5522
|
await geoIdentity();
|
|
5508
5523
|
break;
|
|
5509
5524
|
}
|
|
5510
5525
|
case "6": {
|
|
5511
|
-
const { geoSchema } = await import("./geo-
|
|
5526
|
+
const { geoSchema } = await import("./geo-IRUGSLZS.js");
|
|
5512
5527
|
await geoSchema({});
|
|
5513
5528
|
break;
|
|
5514
5529
|
}
|
|
@@ -5855,25 +5870,7 @@ function Dashboard() {
|
|
|
5855
5870
|
usage: null,
|
|
5856
5871
|
selectedTab: "atoms"
|
|
5857
5872
|
});
|
|
5858
|
-
const fetchUsageSnapshot = async (
|
|
5859
|
-
if (!accessToken) return null;
|
|
5860
|
-
try {
|
|
5861
|
-
const response = await fetch(`${API_URL}/api/usage`, {
|
|
5862
|
-
headers: { Authorization: `Bearer ${accessToken}` }
|
|
5863
|
-
});
|
|
5864
|
-
if (!response.ok) return null;
|
|
5865
|
-
const data = await response.json();
|
|
5866
|
-
const periodLabel = data.periodStart && data.periodEnd ? `Period: ${new Date(data.periodStart).toLocaleDateString()} \u2192 ${new Date(data.periodEnd).toLocaleDateString()}` : void 0;
|
|
5867
|
-
return {
|
|
5868
|
-
usedThisPeriod: data.totalMarkedUpCost ?? data.totalBaseCost ?? 0,
|
|
5869
|
-
periodLabel,
|
|
5870
|
-
tier: data.tier,
|
|
5871
|
-
credits: data.remainingCredits
|
|
5872
|
-
};
|
|
5873
|
-
} catch {
|
|
5874
|
-
return null;
|
|
5875
|
-
}
|
|
5876
|
-
};
|
|
5873
|
+
const fetchUsageSnapshot = async () => null;
|
|
5877
5874
|
const loadData = async () => {
|
|
5878
5875
|
setState((s) => ({ ...s, loading: true }));
|
|
5879
5876
|
try {
|
|
@@ -5887,7 +5884,7 @@ function Dashboard() {
|
|
|
5887
5884
|
const configData = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
5888
5885
|
credits = configData.credits ?? 0;
|
|
5889
5886
|
tier = configData.tier ?? "FREE";
|
|
5890
|
-
usage = await fetchUsageSnapshot(
|
|
5887
|
+
usage = await fetchUsageSnapshot();
|
|
5891
5888
|
if (usage?.credits !== void 0) {
|
|
5892
5889
|
credits = usage.credits;
|
|
5893
5890
|
}
|
|
@@ -6194,251 +6191,279 @@ function generateYamlFrontmatter(rules) {
|
|
|
6194
6191
|
return lines.join("\n") + "\n";
|
|
6195
6192
|
}
|
|
6196
6193
|
|
|
6197
|
-
// src/cli/
|
|
6194
|
+
// src/cli/brand.ts
|
|
6195
|
+
import { Command as Command2 } from "commander";
|
|
6198
6196
|
import chalk8 from "chalk";
|
|
6199
|
-
import
|
|
6200
|
-
import os from "os";
|
|
6201
|
-
import { readFile as readFile6, writeFile as writeFile6 } from "fs/promises";
|
|
6197
|
+
import { writeFile as writeFile6, mkdir as mkdir3 } from "fs/promises";
|
|
6202
6198
|
import { existsSync as existsSync10 } from "fs";
|
|
6203
6199
|
import { join as join9 } from "path";
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
}
|
|
6207
|
-
|
|
6208
|
-
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
const archonConfigPath = join9(cwd, ".archon", "config.yaml");
|
|
6212
|
-
const packageJsonPath = join9(cwd, "package.json");
|
|
6213
|
-
let projectName = "Unknown Project";
|
|
6214
|
-
if (existsSync10(packageJsonPath)) {
|
|
6215
|
-
try {
|
|
6216
|
-
const pkg = JSON.parse(await readFile6(packageJsonPath, "utf-8"));
|
|
6217
|
-
projectName = pkg.name || projectName;
|
|
6218
|
-
} catch {
|
|
6219
|
-
}
|
|
6220
|
-
}
|
|
6221
|
-
if (!existsSync10(archonConfigPath)) {
|
|
6222
|
-
return null;
|
|
6223
|
-
}
|
|
6224
|
-
return { name: projectName, path: cwd };
|
|
6225
|
-
}
|
|
6226
|
-
async function getCurrentAtomId(cwd) {
|
|
6227
|
-
const stateFile = join9(cwd, ".archon", "state.json");
|
|
6228
|
-
if (!existsSync10(stateFile)) return null;
|
|
6229
|
-
try {
|
|
6230
|
-
const state = JSON.parse(await readFile6(stateFile, "utf-8"));
|
|
6231
|
-
return state.currentAtomId || null;
|
|
6232
|
-
} catch {
|
|
6233
|
-
return null;
|
|
6234
|
-
}
|
|
6235
|
-
}
|
|
6236
|
-
async function getPendingAtoms(cwd) {
|
|
6237
|
-
const stateFile = join9(cwd, ".archon", "state.json");
|
|
6238
|
-
if (!existsSync10(stateFile)) return [];
|
|
6239
|
-
try {
|
|
6240
|
-
const state = JSON.parse(await readFile6(stateFile, "utf-8"));
|
|
6241
|
-
return state.pendingAtoms || [];
|
|
6242
|
-
} catch {
|
|
6243
|
-
return [];
|
|
6244
|
-
}
|
|
6245
|
-
}
|
|
6246
|
-
async function getFileContent(path2) {
|
|
6247
|
-
if (!existsSync10(path2)) return null;
|
|
6248
|
-
try {
|
|
6249
|
-
return await readFile6(path2, "utf-8");
|
|
6250
|
-
} catch {
|
|
6251
|
-
return null;
|
|
6252
|
-
}
|
|
6200
|
+
import { createInterface } from "readline";
|
|
6201
|
+
function createPrompt() {
|
|
6202
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
6203
|
+
return {
|
|
6204
|
+
ask: (q) => new Promise((resolve2) => rl.question(q, resolve2)),
|
|
6205
|
+
close: () => rl.close()
|
|
6206
|
+
};
|
|
6253
6207
|
}
|
|
6254
|
-
|
|
6255
|
-
|
|
6208
|
+
var MEMORY_MAP_SYSTEM_PROMPT = `You are a brand strategist with an editorial temperament. Your job is to find what a company is ACTUALLY memorable for \u2014 not what it wishes it were memorable for.
|
|
6209
|
+
|
|
6210
|
+
You are respectful but relentless. You do not accept vague language. You push until answers are specific.
|
|
6211
|
+
|
|
6212
|
+
You apply these tests strictly:
|
|
6213
|
+
|
|
6214
|
+
REJECTION CRITERIA: reject answers that lean on these words as the core memory:
|
|
6215
|
+
${[...BANNED_WORDS_GENERIC, ...BANNED_WORDS_AI_WASHING].join(", ")}
|
|
6216
|
+
|
|
6217
|
+
COMPETITOR TEST: could any direct competitor make the same claim after one brainstorm?
|
|
6218
|
+
If yes, this is category furniture, not memory.
|
|
6219
|
+
|
|
6220
|
+
ABSTRACTION TEST: if the answer is abstract ("more productive"), demand:
|
|
6221
|
+
What specific customer outcome, product behavior, or moment creates this impression?
|
|
6222
|
+
|
|
6223
|
+
TWO-THING TEST: if more than one memory is offered, force a single choice.
|
|
6224
|
+
|
|
6225
|
+
Be honest. If the answer fails after 3 rounds of pressure-testing, accept what they have but mark the failure in the final artifact.
|
|
6226
|
+
|
|
6227
|
+
Output strict JSON.`;
|
|
6228
|
+
var MEMORY_MAP_SURFACES = [
|
|
6229
|
+
{ id: "homepage", label: "Homepage", question: "Describe your homepage \u2014 what does someone see and read in the first 10 seconds? Paste the hero section if you can, or describe headline + visual + primary message." },
|
|
6230
|
+
{ id: "demo", label: "Demo / First Product Experience", question: "Describe your typical demo or first product experience. What does someone actually see, click, and experience? What's the moment that's supposed to land?" },
|
|
6231
|
+
{ id: "founder", label: "Founder Narrative", question: "What's the founder or CEO's public narrative? Consistent story in interviews, on social, on stage? If so, what's the core of it?" },
|
|
6232
|
+
{ id: "customerStory", label: "Strongest Customer Story", question: `Pick your strongest customer story \u2014 the one you'd use if you could only share one. What specifically changed for that customer? Not "they improved efficiency" \u2014 what actually happened?` },
|
|
6233
|
+
{ id: "salesOpen", label: "Sales Opening", question: "Describe the first five minutes of a typical sales conversation. What does the rep lead with? What do they emphasize?" },
|
|
6234
|
+
{ id: "firstUse", label: "First-Session Product Experience", question: "When someone uses the product for the first time without guidance, what do they encounter? What's the experience in the first session?" }
|
|
6235
|
+
];
|
|
6236
|
+
async function brandMemoryMap() {
|
|
6256
6237
|
const cwd = process.cwd();
|
|
6238
|
+
const prompt3 = createPrompt();
|
|
6257
6239
|
try {
|
|
6258
|
-
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
}
|
|
6263
|
-
const projectInfo = await getProjectInfo(cwd);
|
|
6264
|
-
if (!projectInfo) {
|
|
6265
|
-
spinner.fail("Not an ArchonDev project. Run: archon init");
|
|
6266
|
-
return;
|
|
6267
|
-
}
|
|
6268
|
-
const supabase = getSupabaseClient(config.accessToken);
|
|
6269
|
-
const { data: profile } = await supabase.from("user_profiles").select("id").eq("auth_id", config.userId).single();
|
|
6270
|
-
if (!profile) {
|
|
6271
|
-
spinner.fail("Could not find user profile");
|
|
6272
|
-
return;
|
|
6273
|
-
}
|
|
6274
|
-
const currentAtomId = await getCurrentAtomId(cwd);
|
|
6275
|
-
const pendingAtoms = await getPendingAtoms(cwd);
|
|
6276
|
-
const progressSnapshot = await getFileContent(join9(cwd, "progress.txt"));
|
|
6277
|
-
const architectureSnapshot = await getFileContent(join9(cwd, "ARCHITECTURE.md"));
|
|
6278
|
-
const sessionData = {
|
|
6279
|
-
user_id: profile.id,
|
|
6280
|
-
project_name: name || projectInfo.name,
|
|
6281
|
-
project_path: projectInfo.path,
|
|
6282
|
-
current_atom_id: currentAtomId,
|
|
6283
|
-
pending_atoms: pendingAtoms,
|
|
6284
|
-
progress_snapshot: progressSnapshot,
|
|
6285
|
-
architecture_snapshot: architectureSnapshot,
|
|
6286
|
-
last_device: getDeviceName(),
|
|
6287
|
-
is_active: true
|
|
6288
|
-
};
|
|
6289
|
-
const { data: session, error } = await supabase.from("sessions").insert(sessionData).select().single();
|
|
6290
|
-
if (error) {
|
|
6291
|
-
spinner.fail(`Failed to save session: ${error.message}`);
|
|
6292
|
-
return;
|
|
6293
|
-
}
|
|
6294
|
-
spinner.succeed(chalk8.green("Session saved!"));
|
|
6295
|
-
console.log();
|
|
6296
|
-
console.log(` ID: ${chalk8.cyan(session.id)}`);
|
|
6297
|
-
console.log(` Project: ${session.project_name}`);
|
|
6298
|
-
console.log(` Device: ${session.last_device}`);
|
|
6299
|
-
console.log();
|
|
6300
|
-
console.log(chalk8.dim(" Resume on another device: archon session resume " + session.id));
|
|
6301
|
-
console.log();
|
|
6302
|
-
} catch (err2) {
|
|
6303
|
-
spinner.fail("Error saving session");
|
|
6304
|
-
console.error(err2);
|
|
6305
|
-
}
|
|
6306
|
-
}
|
|
6307
|
-
async function listSessions() {
|
|
6308
|
-
const spinner = ora("Fetching sessions...").start();
|
|
6309
|
-
try {
|
|
6310
|
-
const config = await loadConfig();
|
|
6311
|
-
if (!config.accessToken || !config.userId) {
|
|
6312
|
-
spinner.fail("Not logged in. Run: archon login");
|
|
6313
|
-
return;
|
|
6314
|
-
}
|
|
6315
|
-
const supabase = getSupabaseClient(config.accessToken);
|
|
6316
|
-
const { data: profile } = await supabase.from("user_profiles").select("id").eq("auth_id", config.userId).single();
|
|
6317
|
-
if (!profile) {
|
|
6318
|
-
spinner.fail("Could not find user profile");
|
|
6319
|
-
return;
|
|
6320
|
-
}
|
|
6321
|
-
const { data: sessions, error } = await supabase.from("sessions").select("*").eq("user_id", profile.id).eq("is_active", true).order("updated_at", { ascending: false }).limit(20);
|
|
6322
|
-
if (error) {
|
|
6323
|
-
spinner.fail(`Failed to fetch sessions: ${error.message}`);
|
|
6324
|
-
return;
|
|
6325
|
-
}
|
|
6326
|
-
spinner.stop();
|
|
6327
|
-
if (!sessions || sessions.length === 0) {
|
|
6328
|
-
console.log(chalk8.yellow("\nNo saved sessions found.\n"));
|
|
6329
|
-
console.log(chalk8.dim(" Save a session: archon session save [name]\n"));
|
|
6330
|
-
return;
|
|
6331
|
-
}
|
|
6332
|
-
console.log();
|
|
6333
|
-
console.log(chalk8.bold("\u{1F4C2} Saved Sessions"));
|
|
6240
|
+
console.log(chalk8.blue("\n\u{1F9E0} Human Memory Map\n"));
|
|
6241
|
+
console.log(chalk8.dim("Pressure-tests what humans actually remember about you, vs. what you wish."));
|
|
6242
|
+
console.log(chalk8.dim("Six surfaces. Three tests. One uncomfortable diagnostic.\n"));
|
|
6243
|
+
const companyDesc = await prompt3.ask(chalk8.bold("What company are we mapping? Name + plain-language description (not the tagline):\n > "));
|
|
6334
6244
|
console.log();
|
|
6335
|
-
|
|
6336
|
-
|
|
6337
|
-
|
|
6338
|
-
|
|
6339
|
-
|
|
6245
|
+
console.log(chalk8.bold("Phase 2 \u2014 The Memory Question\n"));
|
|
6246
|
+
console.log(chalk8.dim("What ONE thing do you want a person to remember after encountering this company once?"));
|
|
6247
|
+
console.log(chalk8.dim(`Not the mission statement. Not the tagline. The actual memory \u2014 "oh right, they're the ones who ___".
|
|
6248
|
+
`));
|
|
6249
|
+
let intendedMemory = await prompt3.ask(" > ");
|
|
6250
|
+
let passedBar = false;
|
|
6251
|
+
for (let round = 1; round <= 3; round++) {
|
|
6252
|
+
const banned = findBannedWords(intendedMemory);
|
|
6253
|
+
if (banned.length > 0) {
|
|
6254
|
+
console.log();
|
|
6255
|
+
console.log(chalk8.yellow(` Round ${round}/3 \u2014 rejection: filler words detected: ${banned.join(", ")}`));
|
|
6256
|
+
console.log(chalk8.dim(" Could a competitor honestly claim the same thing? Sharpen it."));
|
|
6257
|
+
intendedMemory = await prompt3.ask(" > ");
|
|
6258
|
+
continue;
|
|
6259
|
+
}
|
|
6260
|
+
const agent2 = new ArchitectAgent({ temperature: 0.3 });
|
|
6261
|
+
const testPrompt = `Company: ${companyDesc}
|
|
6262
|
+
Claimed memory: "${intendedMemory}"
|
|
6263
|
+
|
|
6264
|
+
Apply the competitor test and the abstraction test. Return JSON:
|
|
6265
|
+
{
|
|
6266
|
+
"passesCompetitorTest": true|false,
|
|
6267
|
+
"competitorTestReason": "one sentence",
|
|
6268
|
+
"passesAbstractionTest": true|false,
|
|
6269
|
+
"abstractionTestReason": "one sentence",
|
|
6270
|
+
"pushback": "if either test fails, give a specific 1-2 sentence pushback the user can act on. Empty if both pass."
|
|
6271
|
+
}`;
|
|
6272
|
+
const response2 = await agent2.client.chat(
|
|
6273
|
+
MEMORY_MAP_SYSTEM_PROMPT,
|
|
6274
|
+
testPrompt,
|
|
6275
|
+
{ temperature: 0.3, maxTokens: 800 }
|
|
6340
6276
|
);
|
|
6341
|
-
|
|
6277
|
+
const m2 = response2.content.match(/\{[\s\S]*\}/);
|
|
6278
|
+
if (!m2) {
|
|
6279
|
+
passedBar = true;
|
|
6280
|
+
break;
|
|
6281
|
+
}
|
|
6282
|
+
const verdict = JSON.parse(m2[0]);
|
|
6283
|
+
if (verdict.passesCompetitorTest && verdict.passesAbstractionTest) {
|
|
6284
|
+
console.log(chalk8.green(` \u2705 Round ${round}/3 \u2014 passed both tests.`));
|
|
6285
|
+
passedBar = true;
|
|
6286
|
+
break;
|
|
6287
|
+
}
|
|
6288
|
+
console.log();
|
|
6289
|
+
console.log(chalk8.yellow(` Round ${round}/3 \u2014 pushback:`));
|
|
6290
|
+
console.log(chalk8.dim(` Competitor test: ${verdict.competitorTestReason}`));
|
|
6291
|
+
console.log(chalk8.dim(` Abstraction test: ${verdict.abstractionTestReason}`));
|
|
6342
6292
|
console.log();
|
|
6293
|
+
console.log(chalk8.bold(` ${verdict.pushback}`));
|
|
6294
|
+
console.log();
|
|
6295
|
+
if (round < 3) {
|
|
6296
|
+
intendedMemory = await prompt3.ask(" Sharpen and retry > ");
|
|
6297
|
+
}
|
|
6343
6298
|
}
|
|
6344
|
-
|
|
6345
|
-
|
|
6346
|
-
spinner.fail("Error fetching sessions");
|
|
6347
|
-
console.error(err2);
|
|
6348
|
-
}
|
|
6349
|
-
}
|
|
6350
|
-
async function resumeSession(sessionId) {
|
|
6351
|
-
const spinner = ora("Resuming session...").start();
|
|
6352
|
-
const cwd = process.cwd();
|
|
6353
|
-
try {
|
|
6354
|
-
const config = await loadConfig();
|
|
6355
|
-
if (!config.accessToken || !config.userId) {
|
|
6356
|
-
spinner.fail("Not logged in. Run: archon login");
|
|
6357
|
-
return;
|
|
6299
|
+
if (!passedBar) {
|
|
6300
|
+
console.log(chalk8.yellow(" After 3 rounds, accepting current memory but marking failed-specificity-bar."));
|
|
6358
6301
|
}
|
|
6359
|
-
const
|
|
6360
|
-
|
|
6361
|
-
|
|
6362
|
-
|
|
6363
|
-
|
|
6302
|
+
const surfaceResponses = {};
|
|
6303
|
+
console.log();
|
|
6304
|
+
console.log(chalk8.bold("Phase 3 \u2014 Surface Walk\n"));
|
|
6305
|
+
for (const s of MEMORY_MAP_SURFACES) {
|
|
6306
|
+
console.log(chalk8.cyan(s.label));
|
|
6307
|
+
console.log(chalk8.dim(` ${s.question}`));
|
|
6308
|
+
surfaceResponses[s.id] = await prompt3.ask(" > ");
|
|
6309
|
+
console.log();
|
|
6364
6310
|
}
|
|
6365
|
-
|
|
6366
|
-
|
|
6367
|
-
|
|
6368
|
-
|
|
6311
|
+
console.log(chalk8.dim("Producing memory map...\n"));
|
|
6312
|
+
const agent = new ArchitectAgent({ temperature: 0.4 });
|
|
6313
|
+
const artifactPrompt = `Company: ${companyDesc}
|
|
6314
|
+
|
|
6315
|
+
Intended memory (refined over ${passedBar ? "pressure testing" : "3 rounds, failed full specificity bar"}):
|
|
6316
|
+
"${intendedMemory}"
|
|
6317
|
+
|
|
6318
|
+
Surface descriptions (what the user said is on each surface):
|
|
6319
|
+
${MEMORY_MAP_SURFACES.map((s) => `- ${s.label}: ${surfaceResponses[s.id]}`).join("\n")}
|
|
6320
|
+
|
|
6321
|
+
Produce a Human Memory Map artifact. For each of the six surfaces, write what memory would ACTUALLY be created from the description provided (be literal \u2014 if nothing memorable, say "No distinct memory \u2014 blends into category noise").
|
|
6322
|
+
|
|
6323
|
+
Then produce:
|
|
6324
|
+
- patternAnalysis: 2-3 paragraphs on whether surfaces reinforce the same memory or pull in different directions
|
|
6325
|
+
- singleSentenceTest:
|
|
6326
|
+
buyerWouldUse: "Find me the one that ___" / "Show me something like ___" \u2014 based on actual surfaces today
|
|
6327
|
+
companyWishesBuyerWouldUse: what you wish they'd say
|
|
6328
|
+
gap: describe the gap. If same, say so.
|
|
6329
|
+
- whatWouldChange: for each surface where the gap is significant, what specifically would have to change
|
|
6330
|
+
- honestAssessment: one paragraph, direct. Is the brand memorable for something specific or is it a blur? Would an agent amplify or flatten it?
|
|
6331
|
+
|
|
6332
|
+
Output JSON:
|
|
6333
|
+
{
|
|
6334
|
+
"comparisons": [{ "surface": "...", "intendedMemory": "...", "memoryActuallyCreated": "...", "gap": "..." }],
|
|
6335
|
+
"patternAnalysis": "...",
|
|
6336
|
+
"singleSentenceTest": { "buyerWouldUse": "...", "companyWishesBuyerWouldUse": "...", "gap": "..." },
|
|
6337
|
+
"whatWouldChange": [{ "surface": "...", "change": "..." }],
|
|
6338
|
+
"honestAssessment": "..."
|
|
6339
|
+
}`;
|
|
6340
|
+
const response = await agent.client.chat(
|
|
6341
|
+
MEMORY_MAP_SYSTEM_PROMPT,
|
|
6342
|
+
artifactPrompt,
|
|
6343
|
+
{ temperature: 0.4, maxTokens: 3500 }
|
|
6344
|
+
);
|
|
6345
|
+
const m = response.content.match(/\{[\s\S]*\}/);
|
|
6346
|
+
if (!m) {
|
|
6347
|
+
console.log(chalk8.red("Failed to produce memory map."));
|
|
6348
|
+
return null;
|
|
6369
6349
|
}
|
|
6370
|
-
const
|
|
6371
|
-
const
|
|
6372
|
-
|
|
6373
|
-
|
|
6374
|
-
|
|
6375
|
-
|
|
6376
|
-
resumedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
6350
|
+
const parsed = JSON.parse(m[0]);
|
|
6351
|
+
const report = {
|
|
6352
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6353
|
+
intendedMemory,
|
|
6354
|
+
passedSpecificityBar: passedBar,
|
|
6355
|
+
...parsed
|
|
6377
6356
|
};
|
|
6378
|
-
|
|
6379
|
-
|
|
6380
|
-
|
|
6381
|
-
|
|
6382
|
-
|
|
6383
|
-
|
|
6384
|
-
|
|
6385
|
-
|
|
6357
|
+
console.log(chalk8.bold("\n=== HUMAN MEMORY MAP ===\n"));
|
|
6358
|
+
console.log(chalk8.bold("Intended memory:"));
|
|
6359
|
+
console.log(` ${report.intendedMemory}`);
|
|
6360
|
+
console.log(chalk8.dim(` (${report.passedSpecificityBar ? "passed" : "FAILED"} specificity bar)`));
|
|
6361
|
+
console.log();
|
|
6362
|
+
console.log(chalk8.bold("Surface-by-surface comparison:"));
|
|
6363
|
+
for (const c of report.comparisons) {
|
|
6364
|
+
console.log(` ${chalk8.cyan(c.surface)}`);
|
|
6365
|
+
console.log(chalk8.dim(` intended: ${c.intendedMemory}`));
|
|
6366
|
+
console.log(chalk8.dim(` actual: ${c.memoryActuallyCreated}`));
|
|
6367
|
+
console.log(chalk8.dim(` gap: ${c.gap}`));
|
|
6386
6368
|
}
|
|
6387
|
-
await supabase.from("sessions").update({ last_device: getDeviceName(), updated_at: (/* @__PURE__ */ new Date()).toISOString() }).eq("id", session.id);
|
|
6388
|
-
spinner.succeed(chalk8.green("Session resumed!"));
|
|
6389
6369
|
console.log();
|
|
6390
|
-
console.log(
|
|
6391
|
-
console.log(`
|
|
6392
|
-
console.log(` Pending: ${session.pending_atoms.length} atoms`);
|
|
6370
|
+
console.log(chalk8.bold("Pattern analysis:"));
|
|
6371
|
+
console.log(chalk8.dim(` ${report.patternAnalysis}`));
|
|
6393
6372
|
console.log();
|
|
6394
|
-
console.log(chalk8.
|
|
6373
|
+
console.log(chalk8.bold("Single-sentence test:"));
|
|
6374
|
+
console.log(chalk8.dim(` Buyer would say: ${report.singleSentenceTest.buyerWouldUse}`));
|
|
6375
|
+
console.log(chalk8.dim(` You wish they'd say: ${report.singleSentenceTest.companyWishesBuyerWouldUse}`));
|
|
6376
|
+
console.log(chalk8.dim(` Gap: ${report.singleSentenceTest.gap}`));
|
|
6395
6377
|
console.log();
|
|
6396
|
-
|
|
6397
|
-
|
|
6398
|
-
|
|
6378
|
+
console.log(chalk8.bold("What would change:"));
|
|
6379
|
+
for (const w of report.whatWouldChange) {
|
|
6380
|
+
console.log(` ${chalk8.cyan(w.surface)}: ${w.change}`);
|
|
6381
|
+
}
|
|
6382
|
+
console.log();
|
|
6383
|
+
console.log(chalk8.bold("Honest assessment:"));
|
|
6384
|
+
console.log(chalk8.dim(` ${report.honestAssessment}`));
|
|
6385
|
+
console.log();
|
|
6386
|
+
const brandDir = join9(cwd, ".archon", "brand");
|
|
6387
|
+
if (!existsSync10(brandDir)) await mkdir3(brandDir, { recursive: true });
|
|
6388
|
+
const outputPath = join9(brandDir, "memory-map.md");
|
|
6389
|
+
await writeFile6(outputPath, renderMemoryMap(report), "utf-8");
|
|
6390
|
+
console.log(chalk8.green(`\u2705 Report saved to ${outputPath}`));
|
|
6391
|
+
return report;
|
|
6392
|
+
} finally {
|
|
6393
|
+
prompt3.close();
|
|
6399
6394
|
}
|
|
6400
6395
|
}
|
|
6396
|
+
function renderMemoryMap(report) {
|
|
6397
|
+
const lines = [];
|
|
6398
|
+
lines.push(`# Human Memory Map`);
|
|
6399
|
+
lines.push(``);
|
|
6400
|
+
lines.push(`Generated: ${report.generatedAt}`);
|
|
6401
|
+
lines.push(``);
|
|
6402
|
+
lines.push(`## Intended Memory`);
|
|
6403
|
+
lines.push(``);
|
|
6404
|
+
lines.push(`> ${report.intendedMemory}`);
|
|
6405
|
+
lines.push(``);
|
|
6406
|
+
lines.push(`Specificity bar: **${report.passedSpecificityBar ? "PASSED" : "FAILED"}** after pressure-testing.`);
|
|
6407
|
+
lines.push(``);
|
|
6408
|
+
lines.push(`## Surface-by-Surface Comparison`);
|
|
6409
|
+
lines.push(``);
|
|
6410
|
+
lines.push(`| Surface | Intended Memory | Memory Actually Created | Gap |`);
|
|
6411
|
+
lines.push(`|---------|-----------------|-------------------------|-----|`);
|
|
6412
|
+
for (const c of report.comparisons) {
|
|
6413
|
+
lines.push(`| ${c.surface} | ${c.intendedMemory.replace(/\|/g, "\\|")} | ${c.memoryActuallyCreated.replace(/\|/g, "\\|")} | ${c.gap.replace(/\|/g, "\\|")} |`);
|
|
6414
|
+
}
|
|
6415
|
+
lines.push(``);
|
|
6416
|
+
lines.push(`## Pattern Analysis`);
|
|
6417
|
+
lines.push(``);
|
|
6418
|
+
lines.push(report.patternAnalysis);
|
|
6419
|
+
lines.push(``);
|
|
6420
|
+
lines.push(`## Single-Sentence Test`);
|
|
6421
|
+
lines.push(``);
|
|
6422
|
+
lines.push(`- **A buyer would actually say:** "${report.singleSentenceTest.buyerWouldUse}"`);
|
|
6423
|
+
lines.push(`- **You wish a buyer would say:** "${report.singleSentenceTest.companyWishesBuyerWouldUse}"`);
|
|
6424
|
+
lines.push(`- **Gap:** ${report.singleSentenceTest.gap}`);
|
|
6425
|
+
lines.push(``);
|
|
6426
|
+
lines.push(`## What Would Have to Change`);
|
|
6427
|
+
lines.push(``);
|
|
6428
|
+
for (const w of report.whatWouldChange) {
|
|
6429
|
+
lines.push(`### ${w.surface}`);
|
|
6430
|
+
lines.push(w.change);
|
|
6431
|
+
lines.push(``);
|
|
6432
|
+
}
|
|
6433
|
+
lines.push(`## Honest Assessment`);
|
|
6434
|
+
lines.push(``);
|
|
6435
|
+
lines.push(report.honestAssessment);
|
|
6436
|
+
return lines.join("\n");
|
|
6437
|
+
}
|
|
6438
|
+
function createBrandCommand() {
|
|
6439
|
+
const cmd = new Command2("brand").description("Human-memory deliverables (the human half of the two-audience framework)").addHelpText(
|
|
6440
|
+
"after",
|
|
6441
|
+
`
|
|
6442
|
+
Examples:
|
|
6443
|
+
archon brand memory-map Pressure-test what humans remember vs. what you wish
|
|
6444
|
+
`
|
|
6445
|
+
);
|
|
6446
|
+
cmd.command("memory-map").description("Run the Human Memory Map diagnostic (six surfaces, three tests, single-sentence test)").action(async () => {
|
|
6447
|
+
await brandMemoryMap();
|
|
6448
|
+
});
|
|
6449
|
+
cmd.action(async () => {
|
|
6450
|
+
await brandMemoryMap();
|
|
6451
|
+
});
|
|
6452
|
+
return cmd;
|
|
6453
|
+
}
|
|
6454
|
+
|
|
6455
|
+
// src/cli/session.ts
|
|
6456
|
+
async function saveSession(_name) {
|
|
6457
|
+
printRetiredRemotePath("Cloud session sync");
|
|
6458
|
+
}
|
|
6459
|
+
async function listSessions() {
|
|
6460
|
+
printRetiredRemotePath("Cloud session sync");
|
|
6461
|
+
}
|
|
6462
|
+
async function resumeSession(_sessionId) {
|
|
6463
|
+
printRetiredRemotePath("Cloud session sync");
|
|
6464
|
+
}
|
|
6401
6465
|
async function syncSession() {
|
|
6402
|
-
|
|
6403
|
-
const cwd = process.cwd();
|
|
6404
|
-
try {
|
|
6405
|
-
const config = await loadConfig();
|
|
6406
|
-
if (!config.accessToken || !config.userId) {
|
|
6407
|
-
spinner.fail("Not logged in. Run: archon login");
|
|
6408
|
-
return;
|
|
6409
|
-
}
|
|
6410
|
-
const stateFile = join9(cwd, ".archon", "state.json");
|
|
6411
|
-
if (!existsSync10(stateFile)) {
|
|
6412
|
-
spinner.info("No active session to sync");
|
|
6413
|
-
return;
|
|
6414
|
-
}
|
|
6415
|
-
const state = JSON.parse(await readFile6(stateFile, "utf-8"));
|
|
6416
|
-
if (!state.resumedFrom) {
|
|
6417
|
-
spinner.info('Session was not resumed from cloud - use "archon session save" to create one');
|
|
6418
|
-
return;
|
|
6419
|
-
}
|
|
6420
|
-
const supabase = getSupabaseClient(config.accessToken);
|
|
6421
|
-
const currentAtomId = await getCurrentAtomId(cwd);
|
|
6422
|
-
const pendingAtoms = await getPendingAtoms(cwd);
|
|
6423
|
-
const progressSnapshot = await getFileContent(join9(cwd, "progress.txt"));
|
|
6424
|
-
const architectureSnapshot = await getFileContent(join9(cwd, "ARCHITECTURE.md"));
|
|
6425
|
-
const { error } = await supabase.from("sessions").update({
|
|
6426
|
-
current_atom_id: currentAtomId,
|
|
6427
|
-
pending_atoms: pendingAtoms,
|
|
6428
|
-
progress_snapshot: progressSnapshot,
|
|
6429
|
-
architecture_snapshot: architectureSnapshot,
|
|
6430
|
-
last_device: getDeviceName(),
|
|
6431
|
-
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
6432
|
-
}).eq("id", state.resumedFrom);
|
|
6433
|
-
if (error) {
|
|
6434
|
-
spinner.fail(`Failed to sync: ${error.message}`);
|
|
6435
|
-
return;
|
|
6436
|
-
}
|
|
6437
|
-
spinner.succeed(chalk8.green("Session synced to cloud"));
|
|
6438
|
-
} catch (err2) {
|
|
6439
|
-
spinner.fail("Error syncing session");
|
|
6440
|
-
console.error(err2);
|
|
6441
|
-
}
|
|
6466
|
+
printRetiredRemotePath("Cloud session sync");
|
|
6442
6467
|
}
|
|
6443
6468
|
|
|
6444
6469
|
// src/cli/deploy.ts
|
|
@@ -6500,7 +6525,7 @@ import chalk10 from "chalk";
|
|
|
6500
6525
|
|
|
6501
6526
|
// src/core/indexing/local.ts
|
|
6502
6527
|
import { existsSync as existsSync12, mkdirSync as mkdirSync2 } from "fs";
|
|
6503
|
-
import { readFile as
|
|
6528
|
+
import { readFile as readFile6 } from "fs/promises";
|
|
6504
6529
|
import { join as join11, extname } from "path";
|
|
6505
6530
|
import { DatabaseSync } from "node:sqlite";
|
|
6506
6531
|
var CHUNK_SIZE = 1e3;
|
|
@@ -6606,7 +6631,7 @@ var LocalIndexer = class {
|
|
|
6606
6631
|
if (!existsSync12(fullPath)) {
|
|
6607
6632
|
return 0;
|
|
6608
6633
|
}
|
|
6609
|
-
const content = await
|
|
6634
|
+
const content = await readFile6(fullPath, "utf-8");
|
|
6610
6635
|
const chunks = this.chunkText(content);
|
|
6611
6636
|
const deleteStmt = this.db.prepare("DELETE FROM embeddings WHERE file_path = ?");
|
|
6612
6637
|
deleteStmt.run(filePath);
|
|
@@ -6687,284 +6712,13 @@ var LocalIndexer = class {
|
|
|
6687
6712
|
}
|
|
6688
6713
|
};
|
|
6689
6714
|
|
|
6690
|
-
// src/core/indexing/cloud.ts
|
|
6691
|
-
import { createClient } from "@supabase/supabase-js";
|
|
6692
|
-
import { readFile as readFile8 } from "fs/promises";
|
|
6693
|
-
import { existsSync as existsSync13 } from "fs";
|
|
6694
|
-
import { join as join12, extname as extname2 } from "path";
|
|
6695
|
-
import { createHash as createHash2 } from "crypto";
|
|
6696
|
-
var CHUNK_SIZE2 = 1e3;
|
|
6697
|
-
var CHUNK_OVERLAP2 = 200;
|
|
6698
|
-
var INDEXABLE_EXTENSIONS2 = /* @__PURE__ */ new Set([
|
|
6699
|
-
".ts",
|
|
6700
|
-
".tsx",
|
|
6701
|
-
".js",
|
|
6702
|
-
".jsx",
|
|
6703
|
-
".py",
|
|
6704
|
-
".rb",
|
|
6705
|
-
".go",
|
|
6706
|
-
".rs",
|
|
6707
|
-
".java",
|
|
6708
|
-
".c",
|
|
6709
|
-
".cpp",
|
|
6710
|
-
".h",
|
|
6711
|
-
".hpp",
|
|
6712
|
-
".cs",
|
|
6713
|
-
".swift",
|
|
6714
|
-
".kt",
|
|
6715
|
-
".scala",
|
|
6716
|
-
".md",
|
|
6717
|
-
".mdx",
|
|
6718
|
-
".txt",
|
|
6719
|
-
".json",
|
|
6720
|
-
".yaml",
|
|
6721
|
-
".yml",
|
|
6722
|
-
".toml",
|
|
6723
|
-
".html",
|
|
6724
|
-
".css",
|
|
6725
|
-
".scss",
|
|
6726
|
-
".less",
|
|
6727
|
-
".vue",
|
|
6728
|
-
".svelte"
|
|
6729
|
-
]);
|
|
6730
|
-
var CloudIndexer = class {
|
|
6731
|
-
config;
|
|
6732
|
-
client;
|
|
6733
|
-
userId = null;
|
|
6734
|
-
constructor(config) {
|
|
6735
|
-
this.config = config;
|
|
6736
|
-
this.client = createClient(config.supabaseUrl, config.supabaseKey);
|
|
6737
|
-
}
|
|
6738
|
-
/**
|
|
6739
|
-
* Set the authenticated user ID
|
|
6740
|
-
*/
|
|
6741
|
-
setUserId(userId) {
|
|
6742
|
-
this.userId = userId;
|
|
6743
|
-
}
|
|
6744
|
-
/**
|
|
6745
|
-
* Generate embedding using OpenAI API
|
|
6746
|
-
*/
|
|
6747
|
-
async embedText(text) {
|
|
6748
|
-
if (this.config.embeddingProvider === "openai") {
|
|
6749
|
-
return this.embedWithOpenAI(text);
|
|
6750
|
-
}
|
|
6751
|
-
throw new Error(`Unsupported embedding provider: ${this.config.embeddingProvider}`);
|
|
6752
|
-
}
|
|
6753
|
-
async embedWithOpenAI(text) {
|
|
6754
|
-
const response = await fetch("https://api.openai.com/v1/embeddings", {
|
|
6755
|
-
method: "POST",
|
|
6756
|
-
headers: {
|
|
6757
|
-
"Authorization": `Bearer ${this.config.embeddingApiKey}`,
|
|
6758
|
-
"Content-Type": "application/json"
|
|
6759
|
-
},
|
|
6760
|
-
body: JSON.stringify({
|
|
6761
|
-
model: "text-embedding-ada-002",
|
|
6762
|
-
input: text.slice(0, 8e3)
|
|
6763
|
-
// Limit input size
|
|
6764
|
-
})
|
|
6765
|
-
});
|
|
6766
|
-
if (!response.ok) {
|
|
6767
|
-
const error = await response.json();
|
|
6768
|
-
throw new Error(`OpenAI embedding failed: ${error.error?.message ?? response.statusText}`);
|
|
6769
|
-
}
|
|
6770
|
-
const data = await response.json();
|
|
6771
|
-
const embedding = data.data[0]?.embedding;
|
|
6772
|
-
if (!embedding) {
|
|
6773
|
-
throw new Error("No embedding returned from OpenAI");
|
|
6774
|
-
}
|
|
6775
|
-
return embedding;
|
|
6776
|
-
}
|
|
6777
|
-
/**
|
|
6778
|
-
* Chunk text into smaller pieces for embedding
|
|
6779
|
-
*/
|
|
6780
|
-
chunkText(text, filePath) {
|
|
6781
|
-
const chunks = [];
|
|
6782
|
-
const header = `File: ${filePath}
|
|
6783
|
-
|
|
6784
|
-
`;
|
|
6785
|
-
let start2 = 0;
|
|
6786
|
-
let index = 0;
|
|
6787
|
-
while (start2 < text.length) {
|
|
6788
|
-
const end = Math.min(start2 + CHUNK_SIZE2, text.length);
|
|
6789
|
-
const chunkText = index === 0 ? header + text.slice(start2, end) : text.slice(start2, end);
|
|
6790
|
-
if (chunkText.trim().length > 0) {
|
|
6791
|
-
chunks.push({ text: chunkText, index });
|
|
6792
|
-
index++;
|
|
6793
|
-
}
|
|
6794
|
-
start2 += CHUNK_SIZE2 - CHUNK_OVERLAP2;
|
|
6795
|
-
}
|
|
6796
|
-
return chunks;
|
|
6797
|
-
}
|
|
6798
|
-
/**
|
|
6799
|
-
* Check if file should be indexed
|
|
6800
|
-
*/
|
|
6801
|
-
isIndexableFile(filePath) {
|
|
6802
|
-
const ext = extname2(filePath).toLowerCase();
|
|
6803
|
-
return INDEXABLE_EXTENSIONS2.has(ext);
|
|
6804
|
-
}
|
|
6805
|
-
/**
|
|
6806
|
-
* Compute file hash for change detection
|
|
6807
|
-
*/
|
|
6808
|
-
async computeFileHash(content) {
|
|
6809
|
-
return createHash2("sha256").update(content).digest("hex").slice(0, 16);
|
|
6810
|
-
}
|
|
6811
|
-
/**
|
|
6812
|
-
* Index a single file
|
|
6813
|
-
*/
|
|
6814
|
-
async indexFile(cwd, filePath) {
|
|
6815
|
-
if (!this.userId) {
|
|
6816
|
-
throw new Error("User ID not set. Call setUserId() first.");
|
|
6817
|
-
}
|
|
6818
|
-
if (!this.isIndexableFile(filePath)) {
|
|
6819
|
-
return 0;
|
|
6820
|
-
}
|
|
6821
|
-
const fullPath = join12(cwd, filePath);
|
|
6822
|
-
if (!existsSync13(fullPath)) {
|
|
6823
|
-
return 0;
|
|
6824
|
-
}
|
|
6825
|
-
const content = await readFile8(fullPath, "utf-8");
|
|
6826
|
-
const fileHash = await this.computeFileHash(content);
|
|
6827
|
-
const { data: existing } = await this.client.from("code_embeddings").select("file_hash").eq("user_id", this.userId).eq("project_id", this.config.projectId).eq("file_path", filePath).eq("chunk_index", 0).single();
|
|
6828
|
-
if (existing && existing.file_hash === fileHash) {
|
|
6829
|
-
return 0;
|
|
6830
|
-
}
|
|
6831
|
-
await this.client.from("code_embeddings").delete().eq("user_id", this.userId).eq("project_id", this.config.projectId).eq("file_path", filePath);
|
|
6832
|
-
const chunks = this.chunkText(content, filePath);
|
|
6833
|
-
for (const chunk of chunks) {
|
|
6834
|
-
const embedding = await this.embedText(chunk.text);
|
|
6835
|
-
const embeddingStr = `[${embedding.join(",")}]`;
|
|
6836
|
-
await this.client.from("code_embeddings").insert({
|
|
6837
|
-
user_id: this.userId,
|
|
6838
|
-
project_id: this.config.projectId,
|
|
6839
|
-
file_path: filePath,
|
|
6840
|
-
chunk_index: chunk.index,
|
|
6841
|
-
chunk_text: chunk.text,
|
|
6842
|
-
embedding: embeddingStr,
|
|
6843
|
-
file_hash: fileHash
|
|
6844
|
-
});
|
|
6845
|
-
}
|
|
6846
|
-
return chunks.length;
|
|
6847
|
-
}
|
|
6848
|
-
/**
|
|
6849
|
-
* Search for similar code
|
|
6850
|
-
*/
|
|
6851
|
-
async search(query, limit = 10) {
|
|
6852
|
-
if (!this.userId) {
|
|
6853
|
-
throw new Error("User ID not set. Call setUserId() first.");
|
|
6854
|
-
}
|
|
6855
|
-
const queryEmbedding = await this.embedText(query);
|
|
6856
|
-
const embeddingStr = `[${queryEmbedding.join(",")}]`;
|
|
6857
|
-
const { data, error } = await this.client.rpc("search_code_embeddings", {
|
|
6858
|
-
p_user_id: this.userId,
|
|
6859
|
-
p_project_id: this.config.projectId,
|
|
6860
|
-
p_query_embedding: embeddingStr,
|
|
6861
|
-
p_limit: limit
|
|
6862
|
-
});
|
|
6863
|
-
if (error) {
|
|
6864
|
-
throw new Error(`Search failed: ${error.message}`);
|
|
6865
|
-
}
|
|
6866
|
-
return (data ?? []).map((row) => ({
|
|
6867
|
-
file: row.file_path,
|
|
6868
|
-
text: row.chunk_text,
|
|
6869
|
-
score: row.similarity
|
|
6870
|
-
}));
|
|
6871
|
-
}
|
|
6872
|
-
/**
|
|
6873
|
-
* Get indexing status for project
|
|
6874
|
-
*/
|
|
6875
|
-
async getStatus() {
|
|
6876
|
-
if (!this.userId) {
|
|
6877
|
-
throw new Error("User ID not set. Call setUserId() first.");
|
|
6878
|
-
}
|
|
6879
|
-
const { data: fileCount } = await this.client.from("code_embeddings").select("file_path", { count: "exact", head: true }).eq("user_id", this.userId).eq("project_id", this.config.projectId);
|
|
6880
|
-
const { data: chunkCount } = await this.client.from("code_embeddings").select("id", { count: "exact", head: true }).eq("user_id", this.userId).eq("project_id", this.config.projectId);
|
|
6881
|
-
const { data: lastUpdated } = await this.client.from("code_embeddings").select("updated_at").eq("user_id", this.userId).eq("project_id", this.config.projectId).order("updated_at", { ascending: false }).limit(1).single();
|
|
6882
|
-
const { data: job } = await this.client.from("indexing_jobs").select("status").eq("user_id", this.userId).eq("project_id", this.config.projectId).order("created_at", { ascending: false }).limit(1).single();
|
|
6883
|
-
return {
|
|
6884
|
-
projectId: this.config.projectId,
|
|
6885
|
-
fileCount: fileCount?.count ?? 0,
|
|
6886
|
-
chunkCount: chunkCount?.count ?? 0,
|
|
6887
|
-
lastUpdated: lastUpdated?.updated_at ?? null,
|
|
6888
|
-
jobStatus: job?.status
|
|
6889
|
-
};
|
|
6890
|
-
}
|
|
6891
|
-
/**
|
|
6892
|
-
* Remove all embeddings for this project
|
|
6893
|
-
*/
|
|
6894
|
-
async clearProject() {
|
|
6895
|
-
if (!this.userId) {
|
|
6896
|
-
throw new Error("User ID not set. Call setUserId() first.");
|
|
6897
|
-
}
|
|
6898
|
-
await this.client.from("code_embeddings").delete().eq("user_id", this.userId).eq("project_id", this.config.projectId);
|
|
6899
|
-
}
|
|
6900
|
-
/**
|
|
6901
|
-
* Remove a single file from the index
|
|
6902
|
-
*/
|
|
6903
|
-
async removeFile(filePath) {
|
|
6904
|
-
if (!this.userId) {
|
|
6905
|
-
throw new Error("User ID not set. Call setUserId() first.");
|
|
6906
|
-
}
|
|
6907
|
-
await this.client.from("code_embeddings").delete().eq("user_id", this.userId).eq("project_id", this.config.projectId).eq("file_path", filePath);
|
|
6908
|
-
}
|
|
6909
|
-
};
|
|
6910
|
-
|
|
6911
6715
|
// src/cli/index-cmd.ts
|
|
6912
6716
|
import { glob } from "glob";
|
|
6913
|
-
import { join as
|
|
6914
|
-
async function getCloudIndexer(cwd) {
|
|
6915
|
-
const config = await loadConfig();
|
|
6916
|
-
const authToken = getAuthToken(config);
|
|
6917
|
-
if (!authToken) {
|
|
6918
|
-
console.error(chalk10.red('Not authenticated. Run "archon login" first.'));
|
|
6919
|
-
return null;
|
|
6920
|
-
}
|
|
6921
|
-
const openaiKey = process.env["OPENAI_API_KEY"];
|
|
6922
|
-
if (!openaiKey) {
|
|
6923
|
-
console.error(chalk10.red("OPENAI_API_KEY environment variable not set."));
|
|
6924
|
-
console.log(chalk10.dim("Cloud indexing requires an OpenAI API key for embeddings."));
|
|
6925
|
-
console.log(chalk10.dim("Set it with: export OPENAI_API_KEY=sk-..."));
|
|
6926
|
-
return null;
|
|
6927
|
-
}
|
|
6928
|
-
const projectId = basename(cwd);
|
|
6929
|
-
const indexer = new CloudIndexer({
|
|
6930
|
-
supabaseUrl: SUPABASE_URL,
|
|
6931
|
-
supabaseKey: SUPABASE_ANON_KEY,
|
|
6932
|
-
embeddingProvider: "openai",
|
|
6933
|
-
embeddingApiKey: openaiKey,
|
|
6934
|
-
projectId
|
|
6935
|
-
});
|
|
6936
|
-
const { createClient: createClient2 } = await import("@supabase/supabase-js");
|
|
6937
|
-
const client = createClient2(SUPABASE_URL, SUPABASE_ANON_KEY, {
|
|
6938
|
-
global: { headers: { Authorization: `Bearer ${authToken}` } }
|
|
6939
|
-
});
|
|
6940
|
-
const { data: { user } } = await client.auth.getUser();
|
|
6941
|
-
if (!user) {
|
|
6942
|
-
console.error(chalk10.red("Failed to get user. Try logging in again."));
|
|
6943
|
-
return null;
|
|
6944
|
-
}
|
|
6945
|
-
const { data: profile } = await client.from("user_profiles").select("id").eq("auth_id", user.id).single();
|
|
6946
|
-
if (!profile) {
|
|
6947
|
-
console.error(chalk10.red("User profile not found."));
|
|
6948
|
-
return null;
|
|
6949
|
-
}
|
|
6950
|
-
indexer.setUserId(profile.id);
|
|
6951
|
-
return indexer;
|
|
6952
|
-
}
|
|
6717
|
+
import { join as join12 } from "path";
|
|
6953
6718
|
async function indexInit(options) {
|
|
6954
6719
|
const cwd = process.cwd();
|
|
6955
6720
|
if (options.cloud) {
|
|
6956
|
-
|
|
6957
|
-
const indexer = await getCloudIndexer(cwd);
|
|
6958
|
-
if (!indexer) return;
|
|
6959
|
-
try {
|
|
6960
|
-
const status2 = await indexer.getStatus();
|
|
6961
|
-
console.log(chalk10.green("\u2713 Cloud indexing configured"));
|
|
6962
|
-
console.log(chalk10.green(`\u2713 Project ID: ${status2.projectId}`));
|
|
6963
|
-
console.log(chalk10.dim("\nRun `archon index update --cloud` to index your codebase."));
|
|
6964
|
-
} catch (error) {
|
|
6965
|
-
console.error(chalk10.red(`Failed to initialize cloud index: ${error instanceof Error ? error.message : String(error)}`));
|
|
6966
|
-
process.exit(1);
|
|
6967
|
-
}
|
|
6721
|
+
printRetiredRemotePath("Cloud semantic indexing");
|
|
6968
6722
|
return;
|
|
6969
6723
|
}
|
|
6970
6724
|
console.log(chalk10.blue("Initializing local semantic index..."));
|
|
@@ -6994,45 +6748,7 @@ async function indexInit(options) {
|
|
|
6994
6748
|
async function indexUpdate(options) {
|
|
6995
6749
|
const cwd = process.cwd();
|
|
6996
6750
|
if (options?.cloud) {
|
|
6997
|
-
|
|
6998
|
-
const indexer = await getCloudIndexer(cwd);
|
|
6999
|
-
if (!indexer) return;
|
|
7000
|
-
try {
|
|
7001
|
-
const files = await glob("**/*.{ts,tsx,js,jsx,py,rb,go,rs,java,md,json,yaml,yml}", {
|
|
7002
|
-
cwd,
|
|
7003
|
-
ignore: ["**/node_modules/**", "**/dist/**", "**/.git/**", "**/build/**", "**/coverage/**"]
|
|
7004
|
-
});
|
|
7005
|
-
console.log(chalk10.dim(`Found ${files.length} files to index...`));
|
|
7006
|
-
console.log(chalk10.dim("This may take a few minutes and will use OpenAI API credits.\n"));
|
|
7007
|
-
let totalChunks = 0;
|
|
7008
|
-
let indexedFiles = 0;
|
|
7009
|
-
let skippedFiles = 0;
|
|
7010
|
-
for (let i = 0; i < files.length; i++) {
|
|
7011
|
-
const file = files[i];
|
|
7012
|
-
if (!file) continue;
|
|
7013
|
-
process.stdout.write(`\r${chalk10.dim(`[${i + 1}/${files.length}] ${file.slice(0, 45).padEnd(45)}`)}`);
|
|
7014
|
-
try {
|
|
7015
|
-
const chunks = await indexer.indexFile(cwd, file);
|
|
7016
|
-
if (chunks > 0) {
|
|
7017
|
-
totalChunks += chunks;
|
|
7018
|
-
indexedFiles++;
|
|
7019
|
-
} else {
|
|
7020
|
-
skippedFiles++;
|
|
7021
|
-
}
|
|
7022
|
-
} catch (error) {
|
|
7023
|
-
console.log(`
|
|
7024
|
-
${chalk10.yellow(`[!] Skipped ${file}: ${error instanceof Error ? error.message : "Unknown error"}`)}`);
|
|
7025
|
-
}
|
|
7026
|
-
}
|
|
7027
|
-
console.log("\r" + " ".repeat(70));
|
|
7028
|
-
console.log(chalk10.green(`\u2713 Indexed ${indexedFiles} files (${totalChunks} chunks)`));
|
|
7029
|
-
if (skippedFiles > 0) {
|
|
7030
|
-
console.log(chalk10.dim(` Skipped ${skippedFiles} unchanged files`));
|
|
7031
|
-
}
|
|
7032
|
-
} catch (error) {
|
|
7033
|
-
console.error(chalk10.red(`Failed to update cloud index: ${error instanceof Error ? error.message : String(error)}`));
|
|
7034
|
-
process.exit(1);
|
|
7035
|
-
}
|
|
6751
|
+
printRetiredRemotePath("Cloud semantic indexing");
|
|
7036
6752
|
return;
|
|
7037
6753
|
}
|
|
7038
6754
|
console.log(chalk10.blue("Updating local semantic index..."));
|
|
@@ -7066,30 +6782,7 @@ ${chalk10.yellow(`[!] Skipped ${file}: ${error instanceof Error ? error.message
|
|
|
7066
6782
|
async function indexSearch(query, options) {
|
|
7067
6783
|
const cwd = process.cwd();
|
|
7068
6784
|
if (options?.cloud) {
|
|
7069
|
-
|
|
7070
|
-
if (!indexer) return;
|
|
7071
|
-
try {
|
|
7072
|
-
console.log(chalk10.dim("Searching cloud index..."));
|
|
7073
|
-
const results = await indexer.search(query, 10);
|
|
7074
|
-
if (results.length === 0) {
|
|
7075
|
-
console.log(chalk10.yellow("\nNo results found."));
|
|
7076
|
-
console.log(chalk10.dim("Try running `archon index update --cloud` first."));
|
|
7077
|
-
} else {
|
|
7078
|
-
console.log(chalk10.blue(`
|
|
7079
|
-
Top ${results.length} results for: "${query}"
|
|
7080
|
-
`));
|
|
7081
|
-
for (const result of results) {
|
|
7082
|
-
const score = (result.score * 100).toFixed(1);
|
|
7083
|
-
console.log(chalk10.green(`[${score}%] ${result.file}`));
|
|
7084
|
-
const preview = result.text.slice(0, 200).replace(/\n/g, " ").trim();
|
|
7085
|
-
console.log(chalk10.dim(` ${preview}${result.text.length > 200 ? "..." : ""}`));
|
|
7086
|
-
console.log();
|
|
7087
|
-
}
|
|
7088
|
-
}
|
|
7089
|
-
} catch (error) {
|
|
7090
|
-
console.error(chalk10.red(`Cloud search failed: ${error instanceof Error ? error.message : String(error)}`));
|
|
7091
|
-
process.exit(1);
|
|
7092
|
-
}
|
|
6785
|
+
printRetiredRemotePath("Cloud semantic indexing");
|
|
7093
6786
|
return;
|
|
7094
6787
|
}
|
|
7095
6788
|
try {
|
|
@@ -7120,23 +6813,7 @@ Top ${results.length} results for: "${query}"
|
|
|
7120
6813
|
async function indexStatus(options) {
|
|
7121
6814
|
const cwd = process.cwd();
|
|
7122
6815
|
if (options?.cloud) {
|
|
7123
|
-
|
|
7124
|
-
if (!indexer) return;
|
|
7125
|
-
try {
|
|
7126
|
-
const status2 = await indexer.getStatus();
|
|
7127
|
-
console.log(chalk10.blue("\nCloud Semantic Index Status\n"));
|
|
7128
|
-
console.log(` Project ID: ${chalk10.green(status2.projectId)}`);
|
|
7129
|
-
console.log(` Files indexed: ${chalk10.green(status2.fileCount)}`);
|
|
7130
|
-
console.log(` Total chunks: ${chalk10.green(status2.chunkCount)}`);
|
|
7131
|
-
console.log(` Last updated: ${status2.lastUpdated ? chalk10.dim(status2.lastUpdated) : chalk10.yellow("Never")}`);
|
|
7132
|
-
if (status2.jobStatus) {
|
|
7133
|
-
console.log(` Job status: ${chalk10.dim(status2.jobStatus)}`);
|
|
7134
|
-
}
|
|
7135
|
-
console.log(` Storage: ${chalk10.dim("Supabase pgvector")}`);
|
|
7136
|
-
} catch (error) {
|
|
7137
|
-
console.error(chalk10.red(`Failed to get cloud status: ${error instanceof Error ? error.message : String(error)}`));
|
|
7138
|
-
process.exit(1);
|
|
7139
|
-
}
|
|
6816
|
+
printRetiredRemotePath("Cloud semantic indexing");
|
|
7140
6817
|
return;
|
|
7141
6818
|
}
|
|
7142
6819
|
try {
|
|
@@ -7147,7 +6824,7 @@ async function indexStatus(options) {
|
|
|
7147
6824
|
console.log(` Files indexed: ${chalk10.green(status2.fileCount)}`);
|
|
7148
6825
|
console.log(` Total chunks: ${chalk10.green(status2.chunkCount)}`);
|
|
7149
6826
|
console.log(` Last updated: ${status2.lastUpdated ? chalk10.dim(status2.lastUpdated) : chalk10.yellow("Never")}`);
|
|
7150
|
-
console.log(` Database: ${chalk10.dim(
|
|
6827
|
+
console.log(` Database: ${chalk10.dim(join12(cwd, ".archon/index.db"))}`);
|
|
7151
6828
|
indexer.close();
|
|
7152
6829
|
} catch (error) {
|
|
7153
6830
|
console.error(chalk10.red(`Failed to get status: ${error instanceof Error ? error.message : String(error)}`));
|
|
@@ -7157,160 +6834,69 @@ async function indexStatus(options) {
|
|
|
7157
6834
|
async function indexClear(options) {
|
|
7158
6835
|
const cwd = process.cwd();
|
|
7159
6836
|
if (options?.cloud) {
|
|
7160
|
-
|
|
7161
|
-
if (!indexer) return;
|
|
7162
|
-
try {
|
|
7163
|
-
console.log(chalk10.yellow("Clearing cloud index..."));
|
|
7164
|
-
await indexer.clearProject();
|
|
7165
|
-
console.log(chalk10.green("\u2713 Cloud index cleared"));
|
|
7166
|
-
} catch (error) {
|
|
7167
|
-
console.error(chalk10.red(`Failed to clear cloud index: ${error instanceof Error ? error.message : String(error)}`));
|
|
7168
|
-
process.exit(1);
|
|
7169
|
-
}
|
|
6837
|
+
printRetiredRemotePath("Cloud semantic indexing");
|
|
7170
6838
|
return;
|
|
7171
6839
|
}
|
|
7172
6840
|
console.log(chalk10.yellow("To clear local index, delete .archon/index.db"));
|
|
7173
6841
|
}
|
|
7174
6842
|
|
|
7175
6843
|
// src/cli/github.ts
|
|
7176
|
-
import chalk11 from "chalk";
|
|
7177
|
-
import open from "open";
|
|
7178
|
-
var API_URL2 = process.env["ARCHONDEV_API_URL"] ?? "https://archondev-api.fly.dev";
|
|
7179
6844
|
async function githubConnect() {
|
|
7180
|
-
|
|
7181
|
-
const authToken = getAuthToken(config);
|
|
7182
|
-
if (!authToken) {
|
|
7183
|
-
console.error(chalk11.red('Not authenticated. Run "archon login" first.'));
|
|
7184
|
-
process.exit(1);
|
|
7185
|
-
}
|
|
7186
|
-
console.log(chalk11.dim("Starting GitHub connection..."));
|
|
7187
|
-
try {
|
|
7188
|
-
const response = await fetch(`${API_URL2}/api/github/connect`, {
|
|
7189
|
-
headers: {
|
|
7190
|
-
"Authorization": `Bearer ${authToken}`
|
|
7191
|
-
}
|
|
7192
|
-
});
|
|
7193
|
-
if (!response.ok) {
|
|
7194
|
-
const error = await response.json();
|
|
7195
|
-
console.error(chalk11.red(error.error ?? "Failed to start GitHub connection"));
|
|
7196
|
-
process.exit(1);
|
|
7197
|
-
}
|
|
7198
|
-
const data = await response.json();
|
|
7199
|
-
console.log(chalk11.dim("\nOpening browser for GitHub authorization..."));
|
|
7200
|
-
console.log(chalk11.dim("If browser does not open, visit:"));
|
|
7201
|
-
console.log(chalk11.blue(data.url));
|
|
7202
|
-
await open(data.url);
|
|
7203
|
-
console.log(chalk11.dim("\nComplete the authorization in your browser."));
|
|
7204
|
-
console.log(chalk11.dim('Then run "archon github status" to verify connection.'));
|
|
7205
|
-
} catch (error) {
|
|
7206
|
-
console.error(chalk11.red(error instanceof Error ? error.message : "Failed to connect"));
|
|
7207
|
-
process.exit(1);
|
|
7208
|
-
}
|
|
6845
|
+
printRetiredRemotePath("GitHub remote integration");
|
|
7209
6846
|
}
|
|
7210
6847
|
async function githubStatus() {
|
|
7211
|
-
|
|
7212
|
-
const authToken = getAuthToken(config);
|
|
7213
|
-
if (!authToken) {
|
|
7214
|
-
console.error(chalk11.red('Not authenticated. Run "archon login" first.'));
|
|
7215
|
-
process.exit(1);
|
|
7216
|
-
}
|
|
7217
|
-
try {
|
|
7218
|
-
const response = await fetch(`${API_URL2}/api/github/status`, {
|
|
7219
|
-
headers: {
|
|
7220
|
-
"Authorization": `Bearer ${authToken}`
|
|
7221
|
-
}
|
|
7222
|
-
});
|
|
7223
|
-
if (!response.ok) {
|
|
7224
|
-
const error = await response.json();
|
|
7225
|
-
console.error(chalk11.red(error.error ?? "Failed to get GitHub status"));
|
|
7226
|
-
process.exit(1);
|
|
7227
|
-
}
|
|
7228
|
-
const data = await response.json();
|
|
7229
|
-
if (data.connected) {
|
|
7230
|
-
console.log(chalk11.green("\u2713 GitHub connected"));
|
|
7231
|
-
console.log(chalk11.dim(` Username: ${data.username}`));
|
|
7232
|
-
console.log(chalk11.dim(` Connected: ${data.connectedAt ? new Date(data.connectedAt).toLocaleDateString() : "Unknown"}`));
|
|
7233
|
-
} else {
|
|
7234
|
-
console.log(chalk11.yellow("GitHub not connected"));
|
|
7235
|
-
console.log(chalk11.dim('Run "archon github connect" to connect your GitHub account.'));
|
|
7236
|
-
}
|
|
7237
|
-
} catch (error) {
|
|
7238
|
-
console.error(chalk11.red(error instanceof Error ? error.message : "Failed to get status"));
|
|
7239
|
-
process.exit(1);
|
|
7240
|
-
}
|
|
6848
|
+
printRetiredRemotePath("GitHub remote integration");
|
|
7241
6849
|
}
|
|
7242
6850
|
async function githubDisconnect() {
|
|
7243
|
-
|
|
7244
|
-
const authToken = getAuthToken(config);
|
|
7245
|
-
if (!authToken) {
|
|
7246
|
-
console.error(chalk11.red('Not authenticated. Run "archon login" first.'));
|
|
7247
|
-
process.exit(1);
|
|
7248
|
-
}
|
|
7249
|
-
try {
|
|
7250
|
-
const response = await fetch(`${API_URL2}/api/github/disconnect`, {
|
|
7251
|
-
method: "DELETE",
|
|
7252
|
-
headers: {
|
|
7253
|
-
"Authorization": `Bearer ${authToken}`
|
|
7254
|
-
}
|
|
7255
|
-
});
|
|
7256
|
-
if (!response.ok) {
|
|
7257
|
-
const error = await response.json();
|
|
7258
|
-
console.error(chalk11.red(error.error ?? "Failed to disconnect GitHub"));
|
|
7259
|
-
process.exit(1);
|
|
7260
|
-
}
|
|
7261
|
-
console.log(chalk11.green("\u2713 GitHub disconnected"));
|
|
7262
|
-
} catch (error) {
|
|
7263
|
-
console.error(chalk11.red(error instanceof Error ? error.message : "Failed to disconnect"));
|
|
7264
|
-
process.exit(1);
|
|
7265
|
-
}
|
|
6851
|
+
printRetiredRemotePath("GitHub remote integration");
|
|
7266
6852
|
}
|
|
7267
6853
|
|
|
7268
6854
|
// src/cli/interview.ts
|
|
7269
|
-
import
|
|
6855
|
+
import chalk11 from "chalk";
|
|
7270
6856
|
import readline2 from "readline";
|
|
7271
|
-
import
|
|
7272
|
-
import { existsSync as
|
|
7273
|
-
import { join as
|
|
6857
|
+
import ora from "ora";
|
|
6858
|
+
import { existsSync as existsSync13, readFileSync as readFileSync5, writeFileSync, mkdirSync as mkdirSync3 } from "fs";
|
|
6859
|
+
import { join as join13 } from "path";
|
|
7274
6860
|
import { randomUUID } from "crypto";
|
|
7275
6861
|
function getConstitutionPath(cwd) {
|
|
7276
|
-
return
|
|
6862
|
+
return join13(cwd, ".archon", "constitution.json");
|
|
7277
6863
|
}
|
|
7278
6864
|
function getDraftPath(cwd) {
|
|
7279
|
-
return
|
|
6865
|
+
return join13(cwd, ".archon", "constitution-draft.json");
|
|
7280
6866
|
}
|
|
7281
6867
|
async function interview(options = {}) {
|
|
7282
6868
|
const cwd = process.cwd();
|
|
7283
|
-
const archonDir =
|
|
7284
|
-
if (!
|
|
6869
|
+
const archonDir = join13(cwd, ".archon");
|
|
6870
|
+
if (!existsSync13(archonDir)) {
|
|
7285
6871
|
mkdirSync3(archonDir, { recursive: true });
|
|
7286
6872
|
}
|
|
7287
|
-
console.log(
|
|
7288
|
-
console.log(
|
|
6873
|
+
console.log(chalk11.bold("\n\u{1F3AF} ArchonDev Project Interview"));
|
|
6874
|
+
console.log(chalk11.dim("Let's define what you're building.\n"));
|
|
7289
6875
|
const constitutionPath = getConstitutionPath(cwd);
|
|
7290
6876
|
const draftPath = getDraftPath(cwd);
|
|
7291
|
-
if (
|
|
6877
|
+
if (existsSync13(constitutionPath)) {
|
|
7292
6878
|
const existing = deserializeConstitution(readFileSync5(constitutionPath, "utf-8"));
|
|
7293
6879
|
if (existing.state === "FROZEN") {
|
|
7294
|
-
console.log(
|
|
7295
|
-
console.log(
|
|
7296
|
-
console.log(
|
|
6880
|
+
console.log(chalk11.yellow("[!] A frozen Constitution already exists."));
|
|
6881
|
+
console.log(chalk11.dim(` Project: ${existing.branding.projectName}`));
|
|
6882
|
+
console.log(chalk11.dim(` Frozen: ${existing.frozenAt?.toISOString()}`));
|
|
7297
6883
|
console.log();
|
|
7298
6884
|
const action = await prompt2("Start a new interview (overwrite) or view existing? (new/view)");
|
|
7299
6885
|
if (action.toLowerCase() === "view") {
|
|
7300
6886
|
console.log("\n" + summarizeConstitution(existing));
|
|
7301
6887
|
return;
|
|
7302
6888
|
} else if (action.toLowerCase() !== "new") {
|
|
7303
|
-
console.log(
|
|
6889
|
+
console.log(chalk11.dim("Cancelled."));
|
|
7304
6890
|
return;
|
|
7305
6891
|
}
|
|
7306
6892
|
}
|
|
7307
6893
|
}
|
|
7308
6894
|
let constitution;
|
|
7309
6895
|
let startPhase = 1;
|
|
7310
|
-
if (
|
|
6896
|
+
if (existsSync13(draftPath) && options.resume !== false) {
|
|
7311
6897
|
const draft = deserializeConstitution(readFileSync5(draftPath, "utf-8"));
|
|
7312
|
-
console.log(
|
|
7313
|
-
console.log(
|
|
6898
|
+
console.log(chalk11.blue("[i] Found draft from previous session."));
|
|
6899
|
+
console.log(chalk11.dim(` Project: ${draft.branding.projectName || "(unnamed)"}`));
|
|
7314
6900
|
console.log();
|
|
7315
6901
|
const resumeChoice = await prompt2("Resume draft or start fresh? (resume/fresh)");
|
|
7316
6902
|
if (resumeChoice.toLowerCase() === "resume") {
|
|
@@ -7322,7 +6908,7 @@ async function interview(options = {}) {
|
|
|
7322
6908
|
break;
|
|
7323
6909
|
}
|
|
7324
6910
|
}
|
|
7325
|
-
console.log(
|
|
6911
|
+
console.log(chalk11.green(`
|
|
7326
6912
|
\u2713 Resuming at Phase ${startPhase}: ${INTERVIEW_PHASES[startPhase]?.name}
|
|
7327
6913
|
`));
|
|
7328
6914
|
} else {
|
|
@@ -7333,19 +6919,19 @@ async function interview(options = {}) {
|
|
|
7333
6919
|
}
|
|
7334
6920
|
if (options.phase && options.phase >= 1 && options.phase <= 5) {
|
|
7335
6921
|
startPhase = options.phase;
|
|
7336
|
-
console.log(
|
|
6922
|
+
console.log(chalk11.dim(`Starting at Phase ${startPhase}...
|
|
7337
6923
|
`));
|
|
7338
6924
|
}
|
|
7339
|
-
console.log(
|
|
7340
|
-
console.log(
|
|
7341
|
-
console.log(
|
|
6925
|
+
console.log(chalk11.dim("\u2500".repeat(40)));
|
|
6926
|
+
console.log(chalk11.dim(formatProgressBar(startPhase)));
|
|
6927
|
+
console.log(chalk11.dim("\u2500".repeat(40)));
|
|
7342
6928
|
console.log();
|
|
7343
6929
|
let currentPhase = startPhase;
|
|
7344
6930
|
while (currentPhase <= 5) {
|
|
7345
6931
|
const result = await runPhase(currentPhase, constitution, cwd);
|
|
7346
6932
|
if (result.action === "exit") {
|
|
7347
6933
|
saveDraft(cwd, constitution);
|
|
7348
|
-
console.log(
|
|
6934
|
+
console.log(chalk11.dim("\nDraft saved. Run `archon interview` to resume.\n"));
|
|
7349
6935
|
return;
|
|
7350
6936
|
}
|
|
7351
6937
|
if (result.action === "back" && currentPhase > 1) {
|
|
@@ -7360,9 +6946,9 @@ async function interview(options = {}) {
|
|
|
7360
6946
|
if (next) {
|
|
7361
6947
|
currentPhase = next;
|
|
7362
6948
|
console.log();
|
|
7363
|
-
console.log(
|
|
7364
|
-
console.log(
|
|
7365
|
-
console.log(
|
|
6949
|
+
console.log(chalk11.dim("\u2500".repeat(40)));
|
|
6950
|
+
console.log(chalk11.dim(formatProgressBar(currentPhase)));
|
|
6951
|
+
console.log(chalk11.dim("\u2500".repeat(40)));
|
|
7366
6952
|
console.log();
|
|
7367
6953
|
} else {
|
|
7368
6954
|
break;
|
|
@@ -7370,9 +6956,9 @@ async function interview(options = {}) {
|
|
|
7370
6956
|
}
|
|
7371
6957
|
const validationResult = validateConstitution(constitution);
|
|
7372
6958
|
if (!validationResult.valid) {
|
|
7373
|
-
console.log(
|
|
6959
|
+
console.log(chalk11.red("\n[!] Constitution has validation errors:\n"));
|
|
7374
6960
|
for (const error of validationResult.errors) {
|
|
7375
|
-
console.log(
|
|
6961
|
+
console.log(chalk11.red(` \u2022 ${error}`));
|
|
7376
6962
|
}
|
|
7377
6963
|
console.log();
|
|
7378
6964
|
const fix = await promptYesNo2("Would you like to go back and fix these?", true);
|
|
@@ -7382,9 +6968,9 @@ async function interview(options = {}) {
|
|
|
7382
6968
|
}
|
|
7383
6969
|
}
|
|
7384
6970
|
if (validationResult.warnings.length > 0) {
|
|
7385
|
-
console.log(
|
|
6971
|
+
console.log(chalk11.yellow("\n[!] Warnings:\n"));
|
|
7386
6972
|
for (const warning of validationResult.warnings) {
|
|
7387
|
-
console.log(
|
|
6973
|
+
console.log(chalk11.yellow(` \u2022 ${warning}`));
|
|
7388
6974
|
}
|
|
7389
6975
|
console.log();
|
|
7390
6976
|
}
|
|
@@ -7394,21 +6980,21 @@ async function interview(options = {}) {
|
|
|
7394
6980
|
constitution.costs = estimateCosts(constitution, config.tier || "FREE");
|
|
7395
6981
|
const challengeResult = analyzeForChallenges(constitution);
|
|
7396
6982
|
if (challengeResult.shouldChallenge) {
|
|
7397
|
-
console.log(
|
|
7398
|
-
console.log(
|
|
6983
|
+
console.log(chalk11.bold("\n\u{1F3AF} Challenge Mode\n"));
|
|
6984
|
+
console.log(chalk11.dim("Let me share some observations about your project scope...\n"));
|
|
7399
6985
|
for (const challenge of challengeResult.challenges) {
|
|
7400
6986
|
const prompt3 = generateChallengePrompt(challenge);
|
|
7401
|
-
const icon = challenge.severity === "critical" ?
|
|
7402
|
-
console.log(`${icon} ${
|
|
7403
|
-
console.log(
|
|
6987
|
+
const icon = challenge.severity === "critical" ? chalk11.red("\u25CF") : chalk11.yellow("\u25CF");
|
|
6988
|
+
console.log(`${icon} ${chalk11.bold(challenge.title)}`);
|
|
6989
|
+
console.log(chalk11.dim(` ${prompt3}`));
|
|
7404
6990
|
console.log();
|
|
7405
6991
|
}
|
|
7406
|
-
console.log(
|
|
6992
|
+
console.log(chalk11.dim("\u2500".repeat(40)));
|
|
7407
6993
|
console.log(summarizeChallenges(challengeResult));
|
|
7408
|
-
console.log(
|
|
6994
|
+
console.log(chalk11.dim("\u2500".repeat(40)));
|
|
7409
6995
|
console.log();
|
|
7410
6996
|
if (challengeResult.featuresToDefer.length > 0) {
|
|
7411
|
-
console.log(
|
|
6997
|
+
console.log(chalk11.bold("Suggested Features to Defer to Post-MVP:\n"));
|
|
7412
6998
|
for (const feature of challengeResult.featuresToDefer) {
|
|
7413
6999
|
console.log(` \u2022 ${feature.name}`);
|
|
7414
7000
|
}
|
|
@@ -7423,58 +7009,58 @@ async function interview(options = {}) {
|
|
|
7423
7009
|
constitution.complexity = calculateComplexity(constitution);
|
|
7424
7010
|
constitution.estimatedBuildHours = estimateBuildHours(constitution.complexity);
|
|
7425
7011
|
constitution.costs = estimateCosts(constitution, config.tier || "FREE");
|
|
7426
|
-
console.log(
|
|
7427
|
-
console.log(
|
|
7428
|
-
console.log(
|
|
7012
|
+
console.log(chalk11.green("\n\u2713 Features deferred. Updated estimates:"));
|
|
7013
|
+
console.log(chalk11.dim(` Complexity: ${constitution.complexity.tier}`));
|
|
7014
|
+
console.log(chalk11.dim(` Build time: ~${Math.round(constitution.estimatedBuildHours)} hours`));
|
|
7429
7015
|
console.log();
|
|
7430
7016
|
saveDraft(cwd, constitution);
|
|
7431
7017
|
}
|
|
7432
7018
|
}
|
|
7433
7019
|
const criticalCount = challengeResult.challenges.filter((c) => c.severity === "critical").length;
|
|
7434
7020
|
if (criticalCount > 0) {
|
|
7435
|
-
console.log(
|
|
7021
|
+
console.log(chalk11.red(`
|
|
7436
7022
|
\u26A0\uFE0F ${criticalCount} critical issue(s) detected.`));
|
|
7437
7023
|
const proceed = await promptYesNo2("Proceed anyway?", false);
|
|
7438
7024
|
if (!proceed) {
|
|
7439
7025
|
saveDraft(cwd, constitution);
|
|
7440
|
-
console.log(
|
|
7026
|
+
console.log(chalk11.dim("\nDraft saved. Address the issues and run `archon interview` again.\n"));
|
|
7441
7027
|
return;
|
|
7442
7028
|
}
|
|
7443
7029
|
}
|
|
7444
7030
|
} else {
|
|
7445
|
-
console.log(
|
|
7031
|
+
console.log(chalk11.green("\n\u2713 Scope looks reasonable! No major concerns detected.\n"));
|
|
7446
7032
|
}
|
|
7447
|
-
console.log(
|
|
7033
|
+
console.log(chalk11.bold("\n\u{1F4CB} Constitution Summary\n"));
|
|
7448
7034
|
console.log(summarizeConstitution(constitution));
|
|
7449
7035
|
console.log();
|
|
7450
7036
|
if (options.dryRun) {
|
|
7451
|
-
console.log(
|
|
7037
|
+
console.log(chalk11.dim("(Dry run mode - not freezing Constitution)"));
|
|
7452
7038
|
saveDraft(cwd, constitution);
|
|
7453
7039
|
return;
|
|
7454
7040
|
}
|
|
7455
7041
|
const confirmFreeze = await promptYesNo2("Freeze this Constitution and start building?", true);
|
|
7456
7042
|
if (!confirmFreeze) {
|
|
7457
7043
|
saveDraft(cwd, constitution);
|
|
7458
|
-
console.log(
|
|
7044
|
+
console.log(chalk11.dim("\nDraft saved. Run `archon interview` to continue.\n"));
|
|
7459
7045
|
return;
|
|
7460
7046
|
}
|
|
7461
|
-
const spinner =
|
|
7047
|
+
const spinner = ora("Freezing Constitution...").start();
|
|
7462
7048
|
try {
|
|
7463
7049
|
const frozen = freezeConstitution(constitution);
|
|
7464
7050
|
writeFileSync(constitutionPath, serializeConstitution(frozen));
|
|
7465
|
-
if (
|
|
7051
|
+
if (existsSync13(draftPath)) {
|
|
7466
7052
|
const { unlinkSync } = await import("fs");
|
|
7467
7053
|
unlinkSync(draftPath);
|
|
7468
7054
|
}
|
|
7469
|
-
spinner.succeed(
|
|
7055
|
+
spinner.succeed(chalk11.green("Constitution frozen!"));
|
|
7470
7056
|
console.log();
|
|
7471
|
-
console.log(
|
|
7472
|
-
console.log(
|
|
7057
|
+
console.log(chalk11.dim(`Hash: ${frozen.hash?.substring(0, 32)}...`));
|
|
7058
|
+
console.log(chalk11.dim(`Saved: ${constitutionPath}`));
|
|
7473
7059
|
console.log();
|
|
7474
|
-
console.log(
|
|
7475
|
-
console.log(` ${
|
|
7476
|
-
console.log(` ${
|
|
7477
|
-
console.log(` ${
|
|
7060
|
+
console.log(chalk11.bold("Next Steps:\n"));
|
|
7061
|
+
console.log(` ${chalk11.cyan("1.")} Run ${chalk11.bold("archon generate")} to create atoms from this Constitution`);
|
|
7062
|
+
console.log(` ${chalk11.cyan("2.")} Run ${chalk11.bold("archon list")} to see generated atoms`);
|
|
7063
|
+
console.log(` ${chalk11.cyan("3.")} Run ${chalk11.bold("archon execute <atom-id>")} to start building`);
|
|
7478
7064
|
console.log();
|
|
7479
7065
|
} catch (err2) {
|
|
7480
7066
|
spinner.fail("Failed to freeze Constitution");
|
|
@@ -7483,18 +7069,18 @@ async function interview(options = {}) {
|
|
|
7483
7069
|
}
|
|
7484
7070
|
async function runPhase(phase, constitution, cwd) {
|
|
7485
7071
|
const phaseInfo = INTERVIEW_PHASES[phase];
|
|
7486
|
-
console.log(
|
|
7487
|
-
console.log(
|
|
7072
|
+
console.log(chalk11.bold(`Phase ${phase}: ${phaseInfo.name}`));
|
|
7073
|
+
console.log(chalk11.dim(phaseInfo.description));
|
|
7488
7074
|
console.log();
|
|
7489
7075
|
const skippable = getSkippableQuestions(phase, constitution);
|
|
7490
7076
|
let updatedConstitution = { ...constitution };
|
|
7491
7077
|
for (const question of phaseInfo.questions) {
|
|
7492
7078
|
if (skippable.includes(question.id)) {
|
|
7493
|
-
console.log(
|
|
7079
|
+
console.log(chalk11.dim(`[\u2713] ${question.prompt.split("?")[0]}... (already answered)`));
|
|
7494
7080
|
continue;
|
|
7495
7081
|
}
|
|
7496
7082
|
if (phase === 5 && question.id === "review_summary") {
|
|
7497
|
-
console.log(
|
|
7083
|
+
console.log(chalk11.bold("\n\u{1F4CB} Current State:\n"));
|
|
7498
7084
|
console.log(summarizeConstitution(updatedConstitution));
|
|
7499
7085
|
console.log();
|
|
7500
7086
|
}
|
|
@@ -7511,14 +7097,14 @@ async function runPhase(phase, constitution, cwd) {
|
|
|
7511
7097
|
if (question.validator) {
|
|
7512
7098
|
const validation = question.validator(answer);
|
|
7513
7099
|
if (!validation.valid) {
|
|
7514
|
-
console.log(
|
|
7100
|
+
console.log(chalk11.red(` ${validation.error}`));
|
|
7515
7101
|
continue;
|
|
7516
7102
|
}
|
|
7517
7103
|
}
|
|
7518
7104
|
const extracted = question.extractor(answer, updatedConstitution);
|
|
7519
7105
|
updatedConstitution = { ...updatedConstitution, ...extracted };
|
|
7520
7106
|
if (question.followUp && answer.length > 10) {
|
|
7521
|
-
console.log(
|
|
7107
|
+
console.log(chalk11.dim(` ${question.followUp}`));
|
|
7522
7108
|
}
|
|
7523
7109
|
}
|
|
7524
7110
|
return { action: "next", constitution: updatedConstitution };
|
|
@@ -7528,7 +7114,7 @@ function saveDraft(cwd, constitution) {
|
|
|
7528
7114
|
writeFileSync(draftPath, serializeConstitution(constitution));
|
|
7529
7115
|
}
|
|
7530
7116
|
async function promptQuestion(question) {
|
|
7531
|
-
const prefix = question.required ?
|
|
7117
|
+
const prefix = question.required ? chalk11.red("*") : " ";
|
|
7532
7118
|
return prompt2(`${prefix} ${question.prompt}`);
|
|
7533
7119
|
}
|
|
7534
7120
|
function prompt2(question) {
|
|
@@ -7537,7 +7123,7 @@ function prompt2(question) {
|
|
|
7537
7123
|
input: process.stdin,
|
|
7538
7124
|
output: process.stdout
|
|
7539
7125
|
});
|
|
7540
|
-
rl.question(`${
|
|
7126
|
+
rl.question(`${chalk11.cyan("?")} ${question}
|
|
7541
7127
|
> `, (answer) => {
|
|
7542
7128
|
rl.close();
|
|
7543
7129
|
resolve2(answer.trim());
|
|
@@ -7551,7 +7137,7 @@ function promptYesNo2(question, defaultValue) {
|
|
|
7551
7137
|
output: process.stdout
|
|
7552
7138
|
});
|
|
7553
7139
|
const hint = defaultValue ? "(Y/n)" : "(y/N)";
|
|
7554
|
-
rl.question(`${
|
|
7140
|
+
rl.question(`${chalk11.cyan("?")} ${question} ${hint}: `, (answer) => {
|
|
7555
7141
|
rl.close();
|
|
7556
7142
|
if (answer.trim() === "") {
|
|
7557
7143
|
resolve2(defaultValue);
|
|
@@ -7565,48 +7151,48 @@ async function showConstitution() {
|
|
|
7565
7151
|
const cwd = process.cwd();
|
|
7566
7152
|
const constitutionPath = getConstitutionPath(cwd);
|
|
7567
7153
|
const draftPath = getDraftPath(cwd);
|
|
7568
|
-
if (
|
|
7154
|
+
if (existsSync13(constitutionPath)) {
|
|
7569
7155
|
const constitution = deserializeConstitution(readFileSync5(constitutionPath, "utf-8"));
|
|
7570
7156
|
console.log(summarizeConstitution(constitution));
|
|
7571
|
-
} else if (
|
|
7157
|
+
} else if (existsSync13(draftPath)) {
|
|
7572
7158
|
const draft = deserializeConstitution(readFileSync5(draftPath, "utf-8"));
|
|
7573
|
-
console.log(
|
|
7159
|
+
console.log(chalk11.yellow("[DRAFT]"));
|
|
7574
7160
|
console.log(summarizeConstitution(draft));
|
|
7575
7161
|
} else {
|
|
7576
|
-
console.log(
|
|
7162
|
+
console.log(chalk11.dim("No Constitution found. Run `archon interview` to create one."));
|
|
7577
7163
|
}
|
|
7578
7164
|
}
|
|
7579
7165
|
async function validateConstitutionCommand() {
|
|
7580
7166
|
const cwd = process.cwd();
|
|
7581
7167
|
const constitutionPath = getConstitutionPath(cwd);
|
|
7582
7168
|
const draftPath = getDraftPath(cwd);
|
|
7583
|
-
const path2 =
|
|
7584
|
-
if (!
|
|
7585
|
-
console.log(
|
|
7169
|
+
const path2 = existsSync13(constitutionPath) ? constitutionPath : draftPath;
|
|
7170
|
+
if (!existsSync13(path2)) {
|
|
7171
|
+
console.log(chalk11.dim("No Constitution found. Run `archon interview` to create one."));
|
|
7586
7172
|
return;
|
|
7587
7173
|
}
|
|
7588
7174
|
const constitution = deserializeConstitution(readFileSync5(path2, "utf-8"));
|
|
7589
7175
|
const result = validateConstitution(constitution);
|
|
7590
7176
|
if (result.valid) {
|
|
7591
|
-
console.log(
|
|
7177
|
+
console.log(chalk11.green("\u2713 Constitution is valid"));
|
|
7592
7178
|
} else {
|
|
7593
|
-
console.log(
|
|
7179
|
+
console.log(chalk11.red("\u2717 Constitution has errors:"));
|
|
7594
7180
|
for (const error of result.errors) {
|
|
7595
|
-
console.log(
|
|
7181
|
+
console.log(chalk11.red(` \u2022 ${error}`));
|
|
7596
7182
|
}
|
|
7597
7183
|
}
|
|
7598
7184
|
if (result.warnings.length > 0) {
|
|
7599
|
-
console.log(
|
|
7185
|
+
console.log(chalk11.yellow("\nWarnings:"));
|
|
7600
7186
|
for (const warning of result.warnings) {
|
|
7601
|
-
console.log(
|
|
7187
|
+
console.log(chalk11.yellow(` \u2022 ${warning}`));
|
|
7602
7188
|
}
|
|
7603
7189
|
}
|
|
7604
7190
|
}
|
|
7605
7191
|
async function exportConstitution(format) {
|
|
7606
7192
|
const cwd = process.cwd();
|
|
7607
7193
|
const constitutionPath = getConstitutionPath(cwd);
|
|
7608
|
-
if (!
|
|
7609
|
-
console.log(
|
|
7194
|
+
if (!existsSync13(constitutionPath)) {
|
|
7195
|
+
console.log(chalk11.dim("No frozen Constitution found."));
|
|
7610
7196
|
return;
|
|
7611
7197
|
}
|
|
7612
7198
|
const constitution = deserializeConstitution(readFileSync5(constitutionPath, "utf-8"));
|
|
@@ -7619,28 +7205,28 @@ async function exportConstitution(format) {
|
|
|
7619
7205
|
console.log(summarizeConstitution(constitution));
|
|
7620
7206
|
break;
|
|
7621
7207
|
default:
|
|
7622
|
-
console.log(
|
|
7208
|
+
console.log(chalk11.red(`Unknown format: ${format}. Use 'json' or 'markdown'.`));
|
|
7623
7209
|
}
|
|
7624
7210
|
}
|
|
7625
7211
|
async function generateAtoms(options = {}) {
|
|
7626
7212
|
const cwd = process.cwd();
|
|
7627
7213
|
const constitutionPath = getConstitutionPath(cwd);
|
|
7628
|
-
if (!
|
|
7629
|
-
console.log(
|
|
7630
|
-
console.log(
|
|
7214
|
+
if (!existsSync13(constitutionPath)) {
|
|
7215
|
+
console.log(chalk11.red("No frozen Constitution found."));
|
|
7216
|
+
console.log(chalk11.dim("Run `archon interview` to create one first."));
|
|
7631
7217
|
return;
|
|
7632
7218
|
}
|
|
7633
7219
|
const constitution = deserializeConstitution(readFileSync5(constitutionPath, "utf-8"));
|
|
7634
7220
|
if (constitution.state !== "FROZEN") {
|
|
7635
|
-
console.log(
|
|
7636
|
-
console.log(
|
|
7221
|
+
console.log(chalk11.yellow("Constitution is not frozen yet."));
|
|
7222
|
+
console.log(chalk11.dim("Complete the interview and freeze before generating atoms."));
|
|
7637
7223
|
return;
|
|
7638
7224
|
}
|
|
7639
|
-
console.log(
|
|
7640
|
-
console.log(
|
|
7641
|
-
console.log(
|
|
7225
|
+
console.log(chalk11.bold("\n\u{1F527} Generating Atoms from Constitution\n"));
|
|
7226
|
+
console.log(chalk11.dim(`Project: ${constitution.branding.projectName}`));
|
|
7227
|
+
console.log(chalk11.dim(`Hash: ${constitution.hash?.substring(0, 16)}...`));
|
|
7642
7228
|
console.log();
|
|
7643
|
-
const spinner =
|
|
7229
|
+
const spinner = ora("Generating atoms...").start();
|
|
7644
7230
|
const result = generateAtomsFromConstitution(constitution, {
|
|
7645
7231
|
includePostMvp: options.includePostMvp,
|
|
7646
7232
|
addSetupAtom: true,
|
|
@@ -7651,34 +7237,34 @@ async function generateAtoms(options = {}) {
|
|
|
7651
7237
|
console.log(summarizeGeneration(result));
|
|
7652
7238
|
console.log();
|
|
7653
7239
|
if (options.dryRun) {
|
|
7654
|
-
console.log(
|
|
7240
|
+
console.log(chalk11.dim("(Dry run - not writing prd.json)"));
|
|
7655
7241
|
return;
|
|
7656
7242
|
}
|
|
7657
|
-
const prdPath = options.output ??
|
|
7243
|
+
const prdPath = options.output ?? join13(cwd, "prd.json");
|
|
7658
7244
|
const prdContent = formatAsPrdJson(result, constitution);
|
|
7659
|
-
if (
|
|
7245
|
+
if (existsSync13(prdPath)) {
|
|
7660
7246
|
const overwrite = await promptYesNo2("prd.json already exists. Overwrite?", false);
|
|
7661
7247
|
if (!overwrite) {
|
|
7662
|
-
console.log(
|
|
7248
|
+
console.log(chalk11.dim("Cancelled. Existing prd.json preserved."));
|
|
7663
7249
|
return;
|
|
7664
7250
|
}
|
|
7665
7251
|
}
|
|
7666
7252
|
writeFileSync(prdPath, JSON.stringify(prdContent, null, 2));
|
|
7667
|
-
console.log(
|
|
7253
|
+
console.log(chalk11.green(`
|
|
7668
7254
|
\u2713 Written to ${prdPath}`));
|
|
7669
7255
|
console.log();
|
|
7670
|
-
console.log(
|
|
7671
|
-
console.log(` ${
|
|
7672
|
-
console.log(` ${
|
|
7673
|
-
console.log(` ${
|
|
7256
|
+
console.log(chalk11.bold("Next Steps:\n"));
|
|
7257
|
+
console.log(` ${chalk11.cyan("1.")} Run ${chalk11.bold("archon list")} to see all atoms`);
|
|
7258
|
+
console.log(` ${chalk11.cyan("2.")} Run ${chalk11.bold("archon execute ATOM-001")} to start building`);
|
|
7259
|
+
console.log(` ${chalk11.cyan("3.")} Run ${chalk11.bold("archon watch")} to monitor progress`);
|
|
7674
7260
|
console.log();
|
|
7675
7261
|
}
|
|
7676
7262
|
|
|
7677
7263
|
// src/cli/eject.ts
|
|
7678
|
-
import
|
|
7679
|
-
import { existsSync as
|
|
7680
|
-
import { readFile as
|
|
7681
|
-
import { join as
|
|
7264
|
+
import chalk12 from "chalk";
|
|
7265
|
+
import { existsSync as existsSync14, rmSync } from "fs";
|
|
7266
|
+
import { readFile as readFile7, writeFile as writeFile7 } from "fs/promises";
|
|
7267
|
+
import { join as join14 } from "path";
|
|
7682
7268
|
import readline3 from "readline";
|
|
7683
7269
|
var ARCHON_FILES = [
|
|
7684
7270
|
".archon/",
|
|
@@ -7692,70 +7278,70 @@ var METADATA_FILES = [
|
|
|
7692
7278
|
];
|
|
7693
7279
|
async function eject(options = {}) {
|
|
7694
7280
|
const cwd = process.cwd();
|
|
7695
|
-
console.log(
|
|
7696
|
-
const archonDir =
|
|
7697
|
-
if (!
|
|
7698
|
-
console.log(
|
|
7281
|
+
console.log(chalk12.blue("\n\u{1F680} ArchonDev Eject\n"));
|
|
7282
|
+
const archonDir = join14(cwd, ".archon");
|
|
7283
|
+
if (!existsSync14(archonDir)) {
|
|
7284
|
+
console.log(chalk12.yellow("This does not appear to be an ArchonDev project (.archon/ not found)."));
|
|
7699
7285
|
return;
|
|
7700
7286
|
}
|
|
7701
|
-
console.log(
|
|
7287
|
+
console.log(chalk12.dim("The following will be removed/modified:\n"));
|
|
7702
7288
|
const filesToRemove = [];
|
|
7703
7289
|
for (const file of ARCHON_FILES) {
|
|
7704
|
-
const filePath =
|
|
7705
|
-
if (
|
|
7290
|
+
const filePath = join14(cwd, file);
|
|
7291
|
+
if (existsSync14(filePath)) {
|
|
7706
7292
|
filesToRemove.push(file);
|
|
7707
|
-
console.log(
|
|
7293
|
+
console.log(chalk12.red(` \u2717 ${file}`));
|
|
7708
7294
|
}
|
|
7709
7295
|
}
|
|
7710
|
-
const archMd =
|
|
7711
|
-
if (
|
|
7712
|
-
console.log(
|
|
7296
|
+
const archMd = join14(cwd, "ARCHITECTURE.md");
|
|
7297
|
+
if (existsSync14(archMd) && !options.keepArchitecture) {
|
|
7298
|
+
console.log(chalk12.yellow(` ? ARCHITECTURE.md (will be kept by default)`));
|
|
7713
7299
|
}
|
|
7714
7300
|
console.log();
|
|
7715
|
-
console.log(
|
|
7301
|
+
console.log(chalk12.dim("Files to be modified:"));
|
|
7716
7302
|
for (const file of METADATA_FILES) {
|
|
7717
|
-
const filePath =
|
|
7718
|
-
if (
|
|
7719
|
-
console.log(
|
|
7303
|
+
const filePath = join14(cwd, file);
|
|
7304
|
+
if (existsSync14(filePath)) {
|
|
7305
|
+
console.log(chalk12.yellow(` \u25CF ${file}`));
|
|
7720
7306
|
}
|
|
7721
7307
|
}
|
|
7722
7308
|
console.log();
|
|
7723
7309
|
if (!options.force) {
|
|
7724
7310
|
const confirmed = await promptYesNo3("This will permanently remove ArchonDev from your project. Continue?", false);
|
|
7725
7311
|
if (!confirmed) {
|
|
7726
|
-
console.log(
|
|
7312
|
+
console.log(chalk12.dim("Eject cancelled."));
|
|
7727
7313
|
return;
|
|
7728
7314
|
}
|
|
7729
7315
|
}
|
|
7730
7316
|
console.log();
|
|
7731
7317
|
const result = await performEject(cwd, options);
|
|
7732
7318
|
if (result.success) {
|
|
7733
|
-
console.log(
|
|
7319
|
+
console.log(chalk12.green("\n\u2705 Eject complete!\n"));
|
|
7734
7320
|
if (result.filesRemoved.length > 0) {
|
|
7735
|
-
console.log(
|
|
7321
|
+
console.log(chalk12.dim("Removed:"));
|
|
7736
7322
|
for (const file of result.filesRemoved) {
|
|
7737
|
-
console.log(
|
|
7323
|
+
console.log(chalk12.dim(` - ${file}`));
|
|
7738
7324
|
}
|
|
7739
7325
|
}
|
|
7740
7326
|
if (result.filesModified.length > 0) {
|
|
7741
|
-
console.log(
|
|
7327
|
+
console.log(chalk12.dim("\nModified:"));
|
|
7742
7328
|
for (const file of result.filesModified) {
|
|
7743
|
-
console.log(
|
|
7329
|
+
console.log(chalk12.dim(` - ${file}`));
|
|
7744
7330
|
}
|
|
7745
7331
|
}
|
|
7746
7332
|
if (result.warnings.length > 0) {
|
|
7747
|
-
console.log(
|
|
7333
|
+
console.log(chalk12.yellow("\nWarnings:"));
|
|
7748
7334
|
for (const warning of result.warnings) {
|
|
7749
|
-
console.log(
|
|
7335
|
+
console.log(chalk12.yellow(` \u26A0\uFE0F ${warning}`));
|
|
7750
7336
|
}
|
|
7751
7337
|
}
|
|
7752
7338
|
console.log();
|
|
7753
|
-
console.log(
|
|
7754
|
-
console.log(
|
|
7339
|
+
console.log(chalk12.blue("Your project is now a standard repository."));
|
|
7340
|
+
console.log(chalk12.dim("Thank you for using ArchonDev!"));
|
|
7755
7341
|
} else {
|
|
7756
|
-
console.log(
|
|
7342
|
+
console.log(chalk12.red("\n\u274C Eject failed."));
|
|
7757
7343
|
for (const warning of result.warnings) {
|
|
7758
|
-
console.log(
|
|
7344
|
+
console.log(chalk12.red(` ${warning}`));
|
|
7759
7345
|
}
|
|
7760
7346
|
}
|
|
7761
7347
|
}
|
|
@@ -7766,8 +7352,8 @@ async function performEject(cwd, options) {
|
|
|
7766
7352
|
filesModified: [],
|
|
7767
7353
|
warnings: []
|
|
7768
7354
|
};
|
|
7769
|
-
const archonDir =
|
|
7770
|
-
if (
|
|
7355
|
+
const archonDir = join14(cwd, ".archon");
|
|
7356
|
+
if (existsSync14(archonDir)) {
|
|
7771
7357
|
try {
|
|
7772
7358
|
rmSync(archonDir, { recursive: true, force: true });
|
|
7773
7359
|
result.filesRemoved.push(".archon/");
|
|
@@ -7775,8 +7361,8 @@ async function performEject(cwd, options) {
|
|
|
7775
7361
|
result.warnings.push(`Failed to remove .archon/: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
7776
7362
|
}
|
|
7777
7363
|
}
|
|
7778
|
-
const prdPath =
|
|
7779
|
-
if (
|
|
7364
|
+
const prdPath = join14(cwd, "prd.json");
|
|
7365
|
+
if (existsSync14(prdPath)) {
|
|
7780
7366
|
try {
|
|
7781
7367
|
rmSync(prdPath);
|
|
7782
7368
|
result.filesRemoved.push("prd.json");
|
|
@@ -7784,8 +7370,8 @@ async function performEject(cwd, options) {
|
|
|
7784
7370
|
result.warnings.push(`Failed to remove prd.json: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
7785
7371
|
}
|
|
7786
7372
|
}
|
|
7787
|
-
const progressPath =
|
|
7788
|
-
if (
|
|
7373
|
+
const progressPath = join14(cwd, "progress.txt");
|
|
7374
|
+
if (existsSync14(progressPath)) {
|
|
7789
7375
|
try {
|
|
7790
7376
|
rmSync(progressPath);
|
|
7791
7377
|
result.filesRemoved.push("progress.txt");
|
|
@@ -7793,8 +7379,8 @@ async function performEject(cwd, options) {
|
|
|
7793
7379
|
result.warnings.push(`Failed to remove progress.txt: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
7794
7380
|
}
|
|
7795
7381
|
}
|
|
7796
|
-
const promptPath =
|
|
7797
|
-
if (
|
|
7382
|
+
const promptPath = join14(cwd, "prompt.md");
|
|
7383
|
+
if (existsSync14(promptPath)) {
|
|
7798
7384
|
try {
|
|
7799
7385
|
rmSync(promptPath);
|
|
7800
7386
|
result.filesRemoved.push("prompt.md");
|
|
@@ -7802,10 +7388,10 @@ async function performEject(cwd, options) {
|
|
|
7802
7388
|
result.warnings.push(`Failed to remove prompt.md: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
7803
7389
|
}
|
|
7804
7390
|
}
|
|
7805
|
-
const pkgPath =
|
|
7806
|
-
if (
|
|
7391
|
+
const pkgPath = join14(cwd, "package.json");
|
|
7392
|
+
if (existsSync14(pkgPath)) {
|
|
7807
7393
|
try {
|
|
7808
|
-
const pkgContent = await
|
|
7394
|
+
const pkgContent = await readFile7(pkgPath, "utf-8");
|
|
7809
7395
|
const pkg = JSON.parse(pkgContent);
|
|
7810
7396
|
let modified = false;
|
|
7811
7397
|
if ("archondev" in pkg) {
|
|
@@ -7830,10 +7416,10 @@ async function performEject(cwd, options) {
|
|
|
7830
7416
|
}
|
|
7831
7417
|
}
|
|
7832
7418
|
if (!options.keepReadme) {
|
|
7833
|
-
const readmePath =
|
|
7834
|
-
if (
|
|
7419
|
+
const readmePath = join14(cwd, "README.md");
|
|
7420
|
+
if (existsSync14(readmePath)) {
|
|
7835
7421
|
try {
|
|
7836
|
-
const content = await
|
|
7422
|
+
const content = await readFile7(readmePath, "utf-8");
|
|
7837
7423
|
const archonPatterns = [
|
|
7838
7424
|
/## ArchonDev[^#]*(?=##|$)/gi,
|
|
7839
7425
|
/\*This project was scaffolded by ArchonDev\.\*/gi,
|
|
@@ -7862,29 +7448,29 @@ async function performEject(cwd, options) {
|
|
|
7862
7448
|
}
|
|
7863
7449
|
async function ejectDryRun() {
|
|
7864
7450
|
const cwd = process.cwd();
|
|
7865
|
-
console.log(
|
|
7866
|
-
const archonDir =
|
|
7867
|
-
if (!
|
|
7868
|
-
console.log(
|
|
7451
|
+
console.log(chalk12.blue("\n\u{1F50D} Eject Dry Run\n"));
|
|
7452
|
+
const archonDir = join14(cwd, ".archon");
|
|
7453
|
+
if (!existsSync14(archonDir)) {
|
|
7454
|
+
console.log(chalk12.yellow("This does not appear to be an ArchonDev project."));
|
|
7869
7455
|
return;
|
|
7870
7456
|
}
|
|
7871
7457
|
console.log("The following would be removed:\n");
|
|
7872
7458
|
for (const file of ARCHON_FILES) {
|
|
7873
|
-
const filePath =
|
|
7874
|
-
if (
|
|
7875
|
-
console.log(
|
|
7459
|
+
const filePath = join14(cwd, file);
|
|
7460
|
+
if (existsSync14(filePath)) {
|
|
7461
|
+
console.log(chalk12.red(` \u2717 ${file}`));
|
|
7876
7462
|
}
|
|
7877
7463
|
}
|
|
7878
7464
|
console.log();
|
|
7879
7465
|
console.log("The following would be modified:\n");
|
|
7880
7466
|
for (const file of METADATA_FILES) {
|
|
7881
|
-
const filePath =
|
|
7882
|
-
if (
|
|
7883
|
-
console.log(
|
|
7467
|
+
const filePath = join14(cwd, file);
|
|
7468
|
+
if (existsSync14(filePath)) {
|
|
7469
|
+
console.log(chalk12.yellow(` \u25CF ${file}`));
|
|
7884
7470
|
}
|
|
7885
7471
|
}
|
|
7886
7472
|
console.log();
|
|
7887
|
-
console.log(
|
|
7473
|
+
console.log(chalk12.dim('Run "archon eject" to proceed.'));
|
|
7888
7474
|
}
|
|
7889
7475
|
function promptYesNo3(question, defaultValue) {
|
|
7890
7476
|
return new Promise((resolve2) => {
|
|
@@ -7893,7 +7479,7 @@ function promptYesNo3(question, defaultValue) {
|
|
|
7893
7479
|
output: process.stdout
|
|
7894
7480
|
});
|
|
7895
7481
|
const hint = defaultValue ? "(Y/n)" : "(y/N)";
|
|
7896
|
-
rl.question(`${
|
|
7482
|
+
rl.question(`${chalk12.cyan("?")} ${question} ${hint}: `, (answer) => {
|
|
7897
7483
|
rl.close();
|
|
7898
7484
|
if (answer.trim() === "") {
|
|
7899
7485
|
resolve2(defaultValue);
|
|
@@ -7905,11 +7491,11 @@ function promptYesNo3(question, defaultValue) {
|
|
|
7905
7491
|
}
|
|
7906
7492
|
|
|
7907
7493
|
// src/cli/revert.ts
|
|
7908
|
-
import
|
|
7494
|
+
import chalk13 from "chalk";
|
|
7909
7495
|
import { execSync as execSync4 } from "child_process";
|
|
7910
|
-
import { existsSync as
|
|
7911
|
-
import { readFile as
|
|
7912
|
-
import { join as
|
|
7496
|
+
import { existsSync as existsSync15 } from "fs";
|
|
7497
|
+
import { readFile as readFile8, writeFile as writeFile8 } from "fs/promises";
|
|
7498
|
+
import { join as join15 } from "path";
|
|
7913
7499
|
import readline4 from "readline";
|
|
7914
7500
|
async function findAtomCommits(limit = 50) {
|
|
7915
7501
|
const cwd = process.cwd();
|
|
@@ -7950,35 +7536,35 @@ async function findAtomCommits(limit = 50) {
|
|
|
7950
7536
|
}
|
|
7951
7537
|
return commits;
|
|
7952
7538
|
} catch (error) {
|
|
7953
|
-
console.error(
|
|
7539
|
+
console.error(chalk13.red("Failed to read git history:"), error instanceof Error ? error.message : "Unknown error");
|
|
7954
7540
|
return [];
|
|
7955
7541
|
}
|
|
7956
7542
|
}
|
|
7957
7543
|
async function historyCommand(options) {
|
|
7958
7544
|
const limit = options.limit ?? 20;
|
|
7959
|
-
console.log(
|
|
7545
|
+
console.log(chalk13.blue("\n\u{1F4DC} Atom Execution History\n"));
|
|
7960
7546
|
const commits = await findAtomCommits(limit);
|
|
7961
7547
|
if (commits.length === 0) {
|
|
7962
|
-
console.log(
|
|
7963
|
-
console.log(
|
|
7548
|
+
console.log(chalk13.dim("No atom commits found in git history."));
|
|
7549
|
+
console.log(chalk13.dim('Atom commits are created when you run "archon execute <atom-id>".'));
|
|
7964
7550
|
return;
|
|
7965
7551
|
}
|
|
7966
|
-
console.log(
|
|
7552
|
+
console.log(chalk13.dim(`Showing ${commits.length} atom commit(s):
|
|
7967
7553
|
`));
|
|
7968
7554
|
for (const commit of commits) {
|
|
7969
7555
|
const shortHash = commit.commitHash.substring(0, 7);
|
|
7970
7556
|
const filesLabel = commit.filesChanged === 1 ? "file" : "files";
|
|
7971
|
-
console.log(`${
|
|
7972
|
-
console.log(
|
|
7973
|
-
console.log(
|
|
7557
|
+
console.log(`${chalk13.yellow(shortHash)} ${chalk13.cyan(commit.atomId)}`);
|
|
7558
|
+
console.log(chalk13.dim(` ${commit.message}`));
|
|
7559
|
+
console.log(chalk13.dim(` ${commit.date} | ${commit.filesChanged} ${filesLabel} changed`));
|
|
7974
7560
|
console.log();
|
|
7975
7561
|
}
|
|
7976
|
-
console.log(
|
|
7977
|
-
console.log(
|
|
7562
|
+
console.log(chalk13.dim("To revert an atom: archon revert <atom-id>"));
|
|
7563
|
+
console.log(chalk13.dim("Or by commit hash: archon revert --commit <hash>"));
|
|
7978
7564
|
}
|
|
7979
7565
|
async function revertCommand(atomIdOrHash, options = {}) {
|
|
7980
7566
|
const cwd = process.cwd();
|
|
7981
|
-
console.log(
|
|
7567
|
+
console.log(chalk13.blue("\n\u23EA Atom Revert\n"));
|
|
7982
7568
|
let commit;
|
|
7983
7569
|
if (atomIdOrHash.match(/^[a-f0-9]{7,40}$/i)) {
|
|
7984
7570
|
const commits = await findAtomCommits(100);
|
|
@@ -7988,64 +7574,64 @@ async function revertCommand(atomIdOrHash, options = {}) {
|
|
|
7988
7574
|
commit = commits.find((c) => c.atomId.toLowerCase() === atomIdOrHash.toLowerCase());
|
|
7989
7575
|
}
|
|
7990
7576
|
if (!commit) {
|
|
7991
|
-
console.log(
|
|
7992
|
-
console.log(
|
|
7577
|
+
console.log(chalk13.red(`No atom commit found for: ${atomIdOrHash}`));
|
|
7578
|
+
console.log(chalk13.dim('Run "archon history" to see available atom commits.'));
|
|
7993
7579
|
return;
|
|
7994
7580
|
}
|
|
7995
|
-
console.log(`Atom: ${
|
|
7996
|
-
console.log(`Commit: ${
|
|
7581
|
+
console.log(`Atom: ${chalk13.cyan(commit.atomId)}`);
|
|
7582
|
+
console.log(`Commit: ${chalk13.yellow(commit.commitHash.substring(0, 7))}`);
|
|
7997
7583
|
console.log(`Message: ${commit.message}`);
|
|
7998
7584
|
console.log(`Date: ${commit.date}`);
|
|
7999
7585
|
console.log(`Files changed: ${commit.filesChanged}`);
|
|
8000
7586
|
console.log();
|
|
8001
7587
|
try {
|
|
8002
|
-
console.log(
|
|
7588
|
+
console.log(chalk13.dim("Changes to be reverted:"));
|
|
8003
7589
|
const diffStat = execSync4(
|
|
8004
7590
|
`git diff --stat ${commit.commitHash}^..${commit.commitHash}`,
|
|
8005
7591
|
{ cwd, encoding: "utf-8" }
|
|
8006
7592
|
);
|
|
8007
|
-
console.log(
|
|
7593
|
+
console.log(chalk13.dim(diffStat));
|
|
8008
7594
|
} catch {
|
|
8009
7595
|
}
|
|
8010
7596
|
if (!options.force) {
|
|
8011
7597
|
const confirmed = await promptYesNo4("Revert this atom commit?", false);
|
|
8012
7598
|
if (!confirmed) {
|
|
8013
|
-
console.log(
|
|
7599
|
+
console.log(chalk13.dim("Revert cancelled."));
|
|
8014
7600
|
return;
|
|
8015
7601
|
}
|
|
8016
7602
|
}
|
|
8017
7603
|
try {
|
|
8018
7604
|
const revertArgs = options.noCommit ? "--no-commit" : "";
|
|
8019
7605
|
execSync4(`git revert ${revertArgs} ${commit.commitHash}`, { cwd, stdio: "pipe" });
|
|
8020
|
-
console.log(
|
|
7606
|
+
console.log(chalk13.green(`
|
|
8021
7607
|
\u2705 Successfully reverted ${commit.atomId}`));
|
|
8022
7608
|
if (options.noCommit) {
|
|
8023
|
-
console.log(
|
|
8024
|
-
console.log(
|
|
7609
|
+
console.log(chalk13.dim("Changes are staged but not committed."));
|
|
7610
|
+
console.log(chalk13.dim('Run "git commit" to finalize the revert.'));
|
|
8025
7611
|
} else {
|
|
8026
|
-
console.log(
|
|
7612
|
+
console.log(chalk13.dim("A new commit has been created to undo the changes."));
|
|
8027
7613
|
}
|
|
8028
7614
|
await updateAtomStatus(commit.atomId, "REVERTED");
|
|
8029
7615
|
} catch (error) {
|
|
8030
7616
|
const errorMsg = error instanceof Error ? error.message : "Unknown error";
|
|
8031
7617
|
if (errorMsg.includes("conflict")) {
|
|
8032
|
-
console.log(
|
|
8033
|
-
console.log(
|
|
8034
|
-
console.log(
|
|
8035
|
-
console.log(
|
|
7618
|
+
console.log(chalk13.yellow("\n\u26A0\uFE0F Merge conflict detected during revert."));
|
|
7619
|
+
console.log(chalk13.dim("Resolve conflicts manually, then:"));
|
|
7620
|
+
console.log(chalk13.dim(" git add ."));
|
|
7621
|
+
console.log(chalk13.dim(" git revert --continue"));
|
|
8036
7622
|
} else {
|
|
8037
|
-
console.log(
|
|
8038
|
-
console.log(
|
|
7623
|
+
console.log(chalk13.red("\n\u274C Revert failed:"), errorMsg);
|
|
7624
|
+
console.log(chalk13.dim("You may need to resolve this manually."));
|
|
8039
7625
|
}
|
|
8040
7626
|
}
|
|
8041
7627
|
}
|
|
8042
7628
|
async function updateAtomStatus(atomId, status2) {
|
|
8043
|
-
const atomPath =
|
|
8044
|
-
if (!
|
|
7629
|
+
const atomPath = join15(process.cwd(), ".archon", "atoms", `${atomId}.json`);
|
|
7630
|
+
if (!existsSync15(atomPath)) {
|
|
8045
7631
|
return;
|
|
8046
7632
|
}
|
|
8047
7633
|
try {
|
|
8048
|
-
const content = await
|
|
7634
|
+
const content = await readFile8(atomPath, "utf-8");
|
|
8049
7635
|
const atom = JSON.parse(content);
|
|
8050
7636
|
atom["status"] = status2;
|
|
8051
7637
|
atom["revertedAt"] = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -8054,10 +7640,10 @@ async function updateAtomStatus(atomId, status2) {
|
|
|
8054
7640
|
}
|
|
8055
7641
|
}
|
|
8056
7642
|
async function revertableAtoms() {
|
|
8057
|
-
console.log(
|
|
7643
|
+
console.log(chalk13.blue("\n\u{1F504} Revertable Atoms\n"));
|
|
8058
7644
|
const commits = await findAtomCommits(30);
|
|
8059
7645
|
if (commits.length === 0) {
|
|
8060
|
-
console.log(
|
|
7646
|
+
console.log(chalk13.dim("No atom commits found."));
|
|
8061
7647
|
return;
|
|
8062
7648
|
}
|
|
8063
7649
|
const atomMap = /* @__PURE__ */ new Map();
|
|
@@ -8066,14 +7652,14 @@ async function revertableAtoms() {
|
|
|
8066
7652
|
atomMap.set(commit.atomId, commit);
|
|
8067
7653
|
}
|
|
8068
7654
|
}
|
|
8069
|
-
console.log(
|
|
7655
|
+
console.log(chalk13.dim(`Found ${atomMap.size} unique atom(s) in history:
|
|
8070
7656
|
`));
|
|
8071
7657
|
for (const [atomId, commit] of atomMap) {
|
|
8072
7658
|
const shortHash = commit.commitHash.substring(0, 7);
|
|
8073
|
-
console.log(` ${
|
|
7659
|
+
console.log(` ${chalk13.cyan(atomId)} ${chalk13.dim(`(${shortHash})`)} - ${commit.message.substring(0, 50)}`);
|
|
8074
7660
|
}
|
|
8075
7661
|
console.log();
|
|
8076
|
-
console.log(
|
|
7662
|
+
console.log(chalk13.dim("To revert: archon revert <atom-id>"));
|
|
8077
7663
|
}
|
|
8078
7664
|
function promptYesNo4(question, defaultValue) {
|
|
8079
7665
|
return new Promise((resolve2) => {
|
|
@@ -8082,7 +7668,7 @@ function promptYesNo4(question, defaultValue) {
|
|
|
8082
7668
|
output: process.stdout
|
|
8083
7669
|
});
|
|
8084
7670
|
const hint = defaultValue ? "(Y/n)" : "(y/N)";
|
|
8085
|
-
rl.question(`${
|
|
7671
|
+
rl.question(`${chalk13.cyan("?")} ${question} ${hint}: `, (answer) => {
|
|
8086
7672
|
rl.close();
|
|
8087
7673
|
if (answer.trim() === "") {
|
|
8088
7674
|
resolve2(defaultValue);
|
|
@@ -8094,121 +7680,54 @@ function promptYesNo4(question, defaultValue) {
|
|
|
8094
7680
|
}
|
|
8095
7681
|
|
|
8096
7682
|
// src/cli/models-sync.ts
|
|
8097
|
-
import
|
|
8098
|
-
async function modelsSync(
|
|
8099
|
-
|
|
8100
|
-
|
|
8101
|
-
if (!supabaseUrl) {
|
|
8102
|
-
console.log(chalk15.red("SUPABASE_URL not set. Cannot trigger remote sync."));
|
|
8103
|
-
console.log(chalk15.dim("Run the pricing check locally instead:"));
|
|
8104
|
-
console.log(chalk15.dim(" npx tsx scripts/update-model-pricing.ts --check"));
|
|
8105
|
-
return;
|
|
8106
|
-
}
|
|
8107
|
-
console.log(chalk15.blue("\n\u{1F504} Triggering model registry sync...\n"));
|
|
8108
|
-
try {
|
|
8109
|
-
const functionUrl = `${supabaseUrl}/functions/v1/model-registry-sync`;
|
|
8110
|
-
const response = await fetch(functionUrl, {
|
|
8111
|
-
method: "POST",
|
|
8112
|
-
headers: {
|
|
8113
|
-
"Authorization": `Bearer ${supabaseKey}`,
|
|
8114
|
-
"Content-Type": "application/json"
|
|
8115
|
-
}
|
|
8116
|
-
});
|
|
8117
|
-
if (!response.ok) {
|
|
8118
|
-
const errorText = await response.text();
|
|
8119
|
-
console.log(chalk15.red(`Sync failed: ${response.status} - ${errorText}`));
|
|
8120
|
-
return;
|
|
8121
|
-
}
|
|
8122
|
-
const result = await response.json();
|
|
8123
|
-
console.log(chalk15.bold("Sync Results:"));
|
|
8124
|
-
console.log(` Providers checked: ${result.providersChecked.join(", ")}`);
|
|
8125
|
-
console.log(` Duration: ${result.durationMs}ms`);
|
|
8126
|
-
console.log();
|
|
8127
|
-
console.log(chalk15.bold("Parse Confidence:"));
|
|
8128
|
-
for (const [provider, score] of Object.entries(result.confidenceScores)) {
|
|
8129
|
-
const pct = (score * 100).toFixed(0);
|
|
8130
|
-
const color = score >= 0.8 ? chalk15.green : score >= 0.5 ? chalk15.yellow : chalk15.red;
|
|
8131
|
-
console.log(` ${provider}: ${color(pct + "%")}`);
|
|
8132
|
-
}
|
|
8133
|
-
console.log();
|
|
8134
|
-
if (result.diffs.length === 0) {
|
|
8135
|
-
console.log(chalk15.green("\u2705 All model pricing is up to date. No changes detected."));
|
|
8136
|
-
} else {
|
|
8137
|
-
const pricingChanges = result.diffs.filter((d) => d.type === "PRICING_CHANGE");
|
|
8138
|
-
const newModels = result.diffs.filter((d) => d.type === "NEW_MODEL");
|
|
8139
|
-
if (pricingChanges.length > 0) {
|
|
8140
|
-
console.log(chalk15.yellow(`\u{1F4B0} Pricing Changes (${pricingChanges.length}):`));
|
|
8141
|
-
for (const d of pricingChanges) {
|
|
8142
|
-
console.log(` ${d.provider}/${chalk15.bold(d.modelId)}`);
|
|
8143
|
-
console.log(` Old: ${chalk15.red(d.oldValue ?? "unknown")}`);
|
|
8144
|
-
console.log(` New: ${chalk15.green(d.newValue ?? "unknown")}`);
|
|
8145
|
-
}
|
|
8146
|
-
console.log();
|
|
8147
|
-
}
|
|
8148
|
-
if (newModels.length > 0) {
|
|
8149
|
-
console.log(chalk15.cyan(`\u{1F195} New Models (${newModels.length}):`));
|
|
8150
|
-
for (const d of newModels) {
|
|
8151
|
-
console.log(` ${d.provider}/${chalk15.bold(d.modelId)}: ${d.details}`);
|
|
8152
|
-
}
|
|
8153
|
-
console.log();
|
|
8154
|
-
}
|
|
8155
|
-
console.log(chalk15.bold(`Applied: ${result.modelsUpdated} updated, ${result.modelsAdded} added`));
|
|
8156
|
-
}
|
|
8157
|
-
if (result.parseErrors.length > 0) {
|
|
8158
|
-
console.log();
|
|
8159
|
-
console.log(chalk15.red(`\u26A0\uFE0F Warnings/Errors (${result.parseErrors.length}):`));
|
|
8160
|
-
for (const err2 of result.parseErrors) {
|
|
8161
|
-
console.log(chalk15.red(` - ${err2}`));
|
|
8162
|
-
}
|
|
8163
|
-
}
|
|
8164
|
-
console.log();
|
|
8165
|
-
} catch (err2) {
|
|
8166
|
-
console.log(chalk15.red(`Failed to run sync: ${err2}`));
|
|
8167
|
-
}
|
|
7683
|
+
import chalk14 from "chalk";
|
|
7684
|
+
async function modelsSync(_options) {
|
|
7685
|
+
printRetiredRemotePath("Remote model registry sync");
|
|
7686
|
+
console.log(chalk14.dim("Model pricing now comes from the bundled local registry."));
|
|
8168
7687
|
}
|
|
8169
7688
|
async function modelsList() {
|
|
8170
7689
|
const { getAllActiveModels, getModelCost, isFreeModel } = await import("./models-D4NV2MVH.js");
|
|
8171
7690
|
const models = getAllActiveModels();
|
|
8172
|
-
console.log(
|
|
7691
|
+
console.log(chalk14.bold("\n\u{1F4CB} Model Registry\n"));
|
|
8173
7692
|
let currentProvider = "";
|
|
8174
7693
|
for (const model of models) {
|
|
8175
7694
|
if (model.provider !== currentProvider) {
|
|
8176
7695
|
currentProvider = model.provider;
|
|
8177
|
-
console.log(
|
|
7696
|
+
console.log(chalk14.bold.blue(`
|
|
8178
7697
|
${currentProvider.toUpperCase()}`));
|
|
8179
|
-
console.log(
|
|
7698
|
+
console.log(chalk14.dim(" \u2500".repeat(40)));
|
|
8180
7699
|
}
|
|
8181
7700
|
const cost = getModelCost(model.modelId);
|
|
8182
7701
|
const free = isFreeModel(model.modelId);
|
|
8183
|
-
const tier = free ?
|
|
8184
|
-
const category = model.category === "thinking" ?
|
|
7702
|
+
const tier = free ? chalk14.green(" [FREE]") : "";
|
|
7703
|
+
const category = model.category === "thinking" ? chalk14.magenta("thinking") : chalk14.cyan("fast");
|
|
8185
7704
|
const inputPrice = cost ? `$${(cost.costPer1kInput * 1e3).toFixed(2)}/1M` : "?";
|
|
8186
7705
|
const outputPrice = cost ? `$${(cost.costPer1kOutput * 1e3).toFixed(2)}/1M` : "?";
|
|
8187
|
-
console.log(` ${
|
|
8188
|
-
console.log(
|
|
7706
|
+
console.log(` ${chalk14.bold(model.modelId)}${tier}`);
|
|
7707
|
+
console.log(chalk14.dim(` ${category} | Input: ${inputPrice} | Output: ${outputPrice}`));
|
|
8189
7708
|
}
|
|
8190
7709
|
console.log();
|
|
8191
7710
|
}
|
|
8192
7711
|
|
|
8193
7712
|
// src/cli/governance.ts
|
|
8194
|
-
import { Command as
|
|
8195
|
-
import
|
|
8196
|
-
import { existsSync as
|
|
8197
|
-
import { readFile as
|
|
8198
|
-
import { join as
|
|
7713
|
+
import { Command as Command3 } from "commander";
|
|
7714
|
+
import chalk15 from "chalk";
|
|
7715
|
+
import { existsSync as existsSync18, readFileSync as readFileSync7 } from "fs";
|
|
7716
|
+
import { readFile as readFile10 } from "fs/promises";
|
|
7717
|
+
import { join as join18 } from "path";
|
|
8199
7718
|
import matter4 from "gray-matter";
|
|
8200
7719
|
|
|
8201
7720
|
// src/core/governance/migrate.ts
|
|
8202
|
-
import { existsSync as
|
|
8203
|
-
import { readFile as
|
|
8204
|
-
import { join as
|
|
7721
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync4 } from "fs";
|
|
7722
|
+
import { readFile as readFile9, writeFile as writeFile9, unlink as unlink3 } from "fs/promises";
|
|
7723
|
+
import { join as join16 } from "path";
|
|
8205
7724
|
import matter2 from "gray-matter";
|
|
8206
7725
|
var LEGACY_ARCH_PATH = "ARCHITECTURE.md";
|
|
8207
|
-
var LEGACY_TASKS_PATH =
|
|
8208
|
-
var ACTIVE_ARCH_PATH2 =
|
|
8209
|
-
var ACTIVE_TASKS_PATH =
|
|
8210
|
-
var ARCHIVE_COMPLETED_PATH =
|
|
8211
|
-
var HISTORY_LEGACY_DIR =
|
|
7726
|
+
var LEGACY_TASKS_PATH = join16(".archon", "current-tasks.md");
|
|
7727
|
+
var ACTIVE_ARCH_PATH2 = join16(".archon", "active", "architecture.md");
|
|
7728
|
+
var ACTIVE_TASKS_PATH = join16(".archon", "active", "tasks.json");
|
|
7729
|
+
var ARCHIVE_COMPLETED_PATH = join16(".archon", "archive", "completed_tasks.jsonl");
|
|
7730
|
+
var HISTORY_LEGACY_DIR = join16(".archon", "history", "legacy");
|
|
8212
7731
|
function parseLegacyTasks(content) {
|
|
8213
7732
|
const result = { active: [], paused: [] };
|
|
8214
7733
|
const activeHeaderMatch = content.match(/##\s+Active\s*\((\d{4}-\d{2}-\d{2})\)/i);
|
|
@@ -8283,12 +7802,12 @@ async function appendJsonLines(path2, items, dryRun) {
|
|
|
8283
7802
|
}
|
|
8284
7803
|
async function archiveLegacyFile(source, destDir, dryRun) {
|
|
8285
7804
|
const fileName = source.split("/").pop() ?? source.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
8286
|
-
const target =
|
|
7805
|
+
const target = join16(destDir, fileName);
|
|
8287
7806
|
if (dryRun) return target;
|
|
8288
|
-
if (!
|
|
7807
|
+
if (!existsSync16(destDir)) {
|
|
8289
7808
|
mkdirSync4(destDir, { recursive: true });
|
|
8290
7809
|
}
|
|
8291
|
-
const content = await
|
|
7810
|
+
const content = await readFile9(source, "utf-8");
|
|
8292
7811
|
await writeFile9(target, content, "utf-8");
|
|
8293
7812
|
return target;
|
|
8294
7813
|
}
|
|
@@ -8304,10 +7823,10 @@ async function migrateLegacyGovernance(options = {}) {
|
|
|
8304
7823
|
};
|
|
8305
7824
|
const store = new GovernanceStore(cwd);
|
|
8306
7825
|
store.ensureStructure();
|
|
8307
|
-
const archPath =
|
|
8308
|
-
const activeArchPath =
|
|
8309
|
-
if (
|
|
8310
|
-
const raw = await
|
|
7826
|
+
const archPath = join16(cwd, LEGACY_ARCH_PATH);
|
|
7827
|
+
const activeArchPath = join16(cwd, ACTIVE_ARCH_PATH2);
|
|
7828
|
+
if (existsSync16(archPath) && !existsSync16(activeArchPath)) {
|
|
7829
|
+
const raw = await readFile9(archPath, "utf-8");
|
|
8311
7830
|
const parsed = matter2(raw);
|
|
8312
7831
|
const content = parsed.content.trim();
|
|
8313
7832
|
if (!content) {
|
|
@@ -8327,53 +7846,53 @@ async function migrateLegacyGovernance(options = {}) {
|
|
|
8327
7846
|
result.migratedArchitecture = true;
|
|
8328
7847
|
}
|
|
8329
7848
|
if (options.removeLegacy) {
|
|
8330
|
-
const archived = await archiveLegacyFile(archPath,
|
|
7849
|
+
const archived = await archiveLegacyFile(archPath, join16(cwd, HISTORY_LEGACY_DIR), !!options.dryRun);
|
|
8331
7850
|
result.archivedLegacyFiles.push(archived);
|
|
8332
7851
|
if (!options.dryRun) {
|
|
8333
7852
|
await unlink3(archPath);
|
|
8334
7853
|
}
|
|
8335
7854
|
}
|
|
8336
7855
|
}
|
|
8337
|
-
const legacyTasksPath =
|
|
8338
|
-
const activeTasksPath =
|
|
8339
|
-
if (
|
|
8340
|
-
const rawTasks = await
|
|
7856
|
+
const legacyTasksPath = join16(cwd, LEGACY_TASKS_PATH);
|
|
7857
|
+
const activeTasksPath = join16(cwd, ACTIVE_TASKS_PATH);
|
|
7858
|
+
if (existsSync16(legacyTasksPath) && !existsSync16(activeTasksPath)) {
|
|
7859
|
+
const rawTasks = await readFile9(legacyTasksPath, "utf-8");
|
|
8341
7860
|
const parsedTasks = parseLegacyTasks(rawTasks);
|
|
8342
7861
|
const { active, completed } = buildTaskEntries(parsedTasks, nowIso);
|
|
8343
7862
|
if (active.length === 0 && completed.length === 0) {
|
|
8344
7863
|
result.warnings.push("Legacy current-tasks.md did not contain actionable items.");
|
|
8345
7864
|
} else {
|
|
8346
7865
|
await writeJson(activeTasksPath, active, !!options.dryRun);
|
|
8347
|
-
await appendJsonLines(
|
|
7866
|
+
await appendJsonLines(join16(cwd, ARCHIVE_COMPLETED_PATH), completed, !!options.dryRun);
|
|
8348
7867
|
result.migratedTasks = true;
|
|
8349
7868
|
}
|
|
8350
7869
|
if (options.removeLegacy) {
|
|
8351
|
-
const archived = await archiveLegacyFile(legacyTasksPath,
|
|
7870
|
+
const archived = await archiveLegacyFile(legacyTasksPath, join16(cwd, HISTORY_LEGACY_DIR), !!options.dryRun);
|
|
8352
7871
|
result.archivedLegacyFiles.push(archived);
|
|
8353
7872
|
if (!options.dryRun) {
|
|
8354
7873
|
await unlink3(legacyTasksPath);
|
|
8355
7874
|
}
|
|
8356
7875
|
}
|
|
8357
7876
|
}
|
|
8358
|
-
if (
|
|
7877
|
+
if (existsSync16(join16(cwd, ACTIVE_ARCH_PATH2)) && existsSync16(join16(cwd, LEGACY_ARCH_PATH))) {
|
|
8359
7878
|
result.warnings.push("Active architecture already exists; legacy ARCHITECTURE.md left untouched.");
|
|
8360
7879
|
}
|
|
8361
|
-
if (
|
|
7880
|
+
if (existsSync16(join16(cwd, ACTIVE_TASKS_PATH)) && existsSync16(join16(cwd, LEGACY_TASKS_PATH))) {
|
|
8362
7881
|
result.warnings.push("Active tasks already exist; legacy current-tasks.md left untouched.");
|
|
8363
7882
|
}
|
|
8364
7883
|
return result;
|
|
8365
7884
|
}
|
|
8366
7885
|
|
|
8367
7886
|
// src/core/governance/sqlite.ts
|
|
8368
|
-
import { existsSync as
|
|
8369
|
-
import { join as
|
|
7887
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync5, readFileSync as readFileSync6 } from "fs";
|
|
7888
|
+
import { join as join17 } from "path";
|
|
8370
7889
|
import matter3 from "gray-matter";
|
|
8371
7890
|
import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
|
|
8372
|
-
var ARCH_PATH =
|
|
8373
|
-
var TASKS_PATH =
|
|
8374
|
-
var HANDOFFS_PATH =
|
|
8375
|
-
var DECISIONS_PATH =
|
|
8376
|
-
var COMPLETED_PATH =
|
|
7891
|
+
var ARCH_PATH = join17(".archon", "active", "architecture.md");
|
|
7892
|
+
var TASKS_PATH = join17(".archon", "active", "tasks.json");
|
|
7893
|
+
var HANDOFFS_PATH = join17(".archon", "history", "handoffs.jsonl");
|
|
7894
|
+
var DECISIONS_PATH = join17(".archon", "history", "decision_log.jsonl");
|
|
7895
|
+
var COMPLETED_PATH = join17(".archon", "archive", "completed_tasks.jsonl");
|
|
8377
7896
|
var GovernanceSqliteView = class {
|
|
8378
7897
|
db = null;
|
|
8379
7898
|
config;
|
|
@@ -8381,11 +7900,11 @@ var GovernanceSqliteView = class {
|
|
|
8381
7900
|
this.config = config;
|
|
8382
7901
|
}
|
|
8383
7902
|
init(cwd) {
|
|
8384
|
-
const archonDir =
|
|
8385
|
-
if (!
|
|
7903
|
+
const archonDir = join17(cwd, ".archon");
|
|
7904
|
+
if (!existsSync17(archonDir)) {
|
|
8386
7905
|
mkdirSync5(archonDir, { recursive: true });
|
|
8387
7906
|
}
|
|
8388
|
-
const dbPath = this.config.inMemory ? ":memory:" :
|
|
7907
|
+
const dbPath = this.config.inMemory ? ":memory:" : join17(cwd, this.config.dbPath ?? ".archon/governance.db");
|
|
8389
7908
|
this.db = new DatabaseSync2(dbPath);
|
|
8390
7909
|
this.db.exec(`
|
|
8391
7910
|
PRAGMA journal_mode = WAL;
|
|
@@ -8455,8 +7974,8 @@ var GovernanceSqliteView = class {
|
|
|
8455
7974
|
architecture: false
|
|
8456
7975
|
};
|
|
8457
7976
|
this.db.exec("DELETE FROM governance_fts; DELETE FROM architecture; DELETE FROM tasks; DELETE FROM completed_tasks; DELETE FROM handoffs; DELETE FROM decisions;");
|
|
8458
|
-
const archPath =
|
|
8459
|
-
if (
|
|
7977
|
+
const archPath = join17(cwd, ARCH_PATH);
|
|
7978
|
+
if (existsSync17(archPath)) {
|
|
8460
7979
|
const raw = readFileSync6(archPath, "utf-8");
|
|
8461
7980
|
const parsed = matter3(raw);
|
|
8462
7981
|
const data = parsed.data;
|
|
@@ -8481,8 +8000,8 @@ var GovernanceSqliteView = class {
|
|
|
8481
8000
|
).run("architecture", archId, content, typeof data["last_updated"] === "string" ? data["last_updated"] : null);
|
|
8482
8001
|
stats.architecture = true;
|
|
8483
8002
|
}
|
|
8484
|
-
const tasksPath =
|
|
8485
|
-
if (
|
|
8003
|
+
const tasksPath = join17(cwd, TASKS_PATH);
|
|
8004
|
+
if (existsSync17(tasksPath)) {
|
|
8486
8005
|
const raw = readFileSync6(tasksPath, "utf-8");
|
|
8487
8006
|
const tasks = JSON.parse(raw);
|
|
8488
8007
|
const insertTask = this.db.prepare(
|
|
@@ -8500,8 +8019,8 @@ ${task.notes}` : ""), task.updated_at ?? task.created_at);
|
|
|
8500
8019
|
stats.tasks += 1;
|
|
8501
8020
|
}
|
|
8502
8021
|
}
|
|
8503
|
-
const completedPath =
|
|
8504
|
-
if (
|
|
8022
|
+
const completedPath = join17(cwd, COMPLETED_PATH);
|
|
8023
|
+
if (existsSync17(completedPath)) {
|
|
8505
8024
|
const lines = readFileSync6(completedPath, "utf-8").split("\n").filter((line) => line.trim().length > 0);
|
|
8506
8025
|
const insertCompleted = this.db.prepare(
|
|
8507
8026
|
`INSERT OR REPLACE INTO completed_tasks (id, description, status, created_at, updated_at, notes)
|
|
@@ -8519,8 +8038,8 @@ ${task.notes}` : ""), task.updated_at ?? task.created_at);
|
|
|
8519
8038
|
stats.completedTasks += 1;
|
|
8520
8039
|
}
|
|
8521
8040
|
}
|
|
8522
|
-
const handoffsPath =
|
|
8523
|
-
if (
|
|
8041
|
+
const handoffsPath = join17(cwd, HANDOFFS_PATH);
|
|
8042
|
+
if (existsSync17(handoffsPath)) {
|
|
8524
8043
|
const lines = readFileSync6(handoffsPath, "utf-8").split("\n").filter((line) => line.trim().length > 0);
|
|
8525
8044
|
const insertHandoff = this.db.prepare(
|
|
8526
8045
|
`INSERT OR REPLACE INTO handoffs (id, timestamp, from_agent, reason, summary, next_actions)
|
|
@@ -8540,8 +8059,8 @@ ${nextActions}`, entry.timestamp);
|
|
|
8540
8059
|
stats.handoffs += 1;
|
|
8541
8060
|
}
|
|
8542
8061
|
}
|
|
8543
|
-
const decisionsPath =
|
|
8544
|
-
if (
|
|
8062
|
+
const decisionsPath = join17(cwd, DECISIONS_PATH);
|
|
8063
|
+
if (existsSync17(decisionsPath)) {
|
|
8545
8064
|
const lines = readFileSync6(decisionsPath, "utf-8").split("\n").filter((line) => line.trim().length > 0);
|
|
8546
8065
|
const insertDecision = this.db.prepare(
|
|
8547
8066
|
`INSERT OR REPLACE INTO decisions (id, timestamp, category, change_reason, updated_by, diff_summary)
|
|
@@ -8632,22 +8151,22 @@ ${entry.diff_summary}` : ""}`, entry.timestamp);
|
|
|
8632
8151
|
};
|
|
8633
8152
|
|
|
8634
8153
|
// src/cli/governance.ts
|
|
8635
|
-
var ACTIVE_ARCH_PATH3 =
|
|
8636
|
-
var ACTIVE_TASKS_PATH2 =
|
|
8637
|
-
var CURRENT_CONTEXT_PATH =
|
|
8638
|
-
var HANDOFF_HISTORY_PATH =
|
|
8639
|
-
var COMPLETED_TASKS_PATH =
|
|
8154
|
+
var ACTIVE_ARCH_PATH3 = join18(".archon", "active", "architecture.md");
|
|
8155
|
+
var ACTIVE_TASKS_PATH2 = join18(".archon", "active", "tasks.json");
|
|
8156
|
+
var CURRENT_CONTEXT_PATH = join18(".archon", "current_context.md");
|
|
8157
|
+
var HANDOFF_HISTORY_PATH = join18(".archon", "history", "handoffs.jsonl");
|
|
8158
|
+
var COMPLETED_TASKS_PATH = join18(".archon", "archive", "completed_tasks.jsonl");
|
|
8640
8159
|
var TASK_STATUSES = ["pending", "in_progress", "verification", "done"];
|
|
8641
8160
|
function isTaskStatus(value) {
|
|
8642
8161
|
return typeof value === "string" && TASK_STATUSES.includes(value);
|
|
8643
8162
|
}
|
|
8644
8163
|
function resolveArchitecturePath2(cwd) {
|
|
8645
|
-
const agdPath =
|
|
8646
|
-
if (
|
|
8164
|
+
const agdPath = join18(cwd, ACTIVE_ARCH_PATH3);
|
|
8165
|
+
if (existsSync18(agdPath)) {
|
|
8647
8166
|
return { path: agdPath, source: "agd" };
|
|
8648
8167
|
}
|
|
8649
|
-
const legacyPath =
|
|
8650
|
-
if (
|
|
8168
|
+
const legacyPath = join18(cwd, "ARCHITECTURE.md");
|
|
8169
|
+
if (existsSync18(legacyPath)) {
|
|
8651
8170
|
return { path: legacyPath, source: "legacy" };
|
|
8652
8171
|
}
|
|
8653
8172
|
return { path: null, source: null };
|
|
@@ -8699,9 +8218,9 @@ function parseContextMeta(content) {
|
|
|
8699
8218
|
function renderStatusCounts(counts) {
|
|
8700
8219
|
const total = Object.values(counts).reduce((sum, value) => sum + value, 0);
|
|
8701
8220
|
if (total === 0) return;
|
|
8702
|
-
console.log(
|
|
8221
|
+
console.log(chalk15.dim(` Tasks: ${total} total`));
|
|
8703
8222
|
console.log(
|
|
8704
|
-
|
|
8223
|
+
chalk15.dim(
|
|
8705
8224
|
` pending: ${counts.pending} | in_progress: ${counts.in_progress} | verification: ${counts.verification} | done: ${counts.done}`
|
|
8706
8225
|
)
|
|
8707
8226
|
);
|
|
@@ -8712,63 +8231,63 @@ function lineCount(content) {
|
|
|
8712
8231
|
return trimmed.split("\n").length;
|
|
8713
8232
|
}
|
|
8714
8233
|
function createGovernanceCommand() {
|
|
8715
|
-
const governance = new
|
|
8234
|
+
const governance = new Command3("governance").alias("gov").description("Manage governance store (AGD)");
|
|
8716
8235
|
governance.command("status").description("Show governance status from AGD store").action(async () => {
|
|
8717
8236
|
const cwd = process.cwd();
|
|
8718
8237
|
const store = new GovernanceStore(cwd);
|
|
8719
8238
|
store.ensureStructure();
|
|
8720
|
-
console.log(
|
|
8239
|
+
console.log(chalk15.bold("\nGovernance Status\n"));
|
|
8721
8240
|
const archInfo = resolveArchitecturePath2(cwd);
|
|
8722
8241
|
if (archInfo.path) {
|
|
8723
8242
|
const parser = new ArchitectureParser(archInfo.path);
|
|
8724
8243
|
const parsed = await parser.parse();
|
|
8725
8244
|
if (parsed.success && parsed.schema) {
|
|
8726
8245
|
const posture = parsed.schema.qualityLevel?.posture ?? "unknown";
|
|
8727
|
-
console.log(
|
|
8728
|
-
console.log(
|
|
8729
|
-
console.log(
|
|
8730
|
-
console.log(
|
|
8246
|
+
console.log(chalk15.green(" \u2713") + ` Architecture (${archInfo.source})`);
|
|
8247
|
+
console.log(chalk15.dim(` posture: ${posture}`));
|
|
8248
|
+
console.log(chalk15.dim(` invariants: ${parsed.schema.invariants.length}`));
|
|
8249
|
+
console.log(chalk15.dim(` protected paths: ${parsed.schema.protectedPaths.length}`));
|
|
8731
8250
|
} else {
|
|
8732
|
-
console.log(
|
|
8251
|
+
console.log(chalk15.yellow(" ! Architecture present but failed to parse"));
|
|
8733
8252
|
}
|
|
8734
8253
|
} else {
|
|
8735
|
-
console.log(
|
|
8254
|
+
console.log(chalk15.yellow(" \u25CB No architecture file found"));
|
|
8736
8255
|
}
|
|
8737
|
-
const tasksPath =
|
|
8738
|
-
if (
|
|
8256
|
+
const tasksPath = join18(cwd, ACTIVE_TASKS_PATH2);
|
|
8257
|
+
if (existsSync18(tasksPath)) {
|
|
8739
8258
|
try {
|
|
8740
8259
|
const tasksRaw = JSON.parse(readFileSync7(tasksPath, "utf-8"));
|
|
8741
8260
|
const tasks2 = parseTasks(tasksRaw);
|
|
8742
8261
|
if (tasks2) {
|
|
8743
8262
|
renderStatusCounts(countTaskStatuses(tasks2));
|
|
8744
8263
|
} else {
|
|
8745
|
-
console.log(
|
|
8264
|
+
console.log(chalk15.yellow(" ! tasks.json present but invalid"));
|
|
8746
8265
|
}
|
|
8747
8266
|
} catch {
|
|
8748
|
-
console.log(
|
|
8267
|
+
console.log(chalk15.yellow(" ! tasks.json present but unreadable"));
|
|
8749
8268
|
}
|
|
8750
8269
|
}
|
|
8751
|
-
const contextPath =
|
|
8752
|
-
if (
|
|
8270
|
+
const contextPath = join18(cwd, CURRENT_CONTEXT_PATH);
|
|
8271
|
+
if (existsSync18(contextPath)) {
|
|
8753
8272
|
const content = readFileSync7(contextPath, "utf-8");
|
|
8754
8273
|
const meta = parseContextMeta(content);
|
|
8755
|
-
console.log(
|
|
8274
|
+
console.log(chalk15.dim(` Handoff: ${meta.timestamp ?? "present"}`));
|
|
8756
8275
|
if (meta.reason) {
|
|
8757
|
-
console.log(
|
|
8276
|
+
console.log(chalk15.dim(` reason: ${meta.reason}`));
|
|
8758
8277
|
}
|
|
8759
8278
|
}
|
|
8760
|
-
const handoffHistoryPath =
|
|
8761
|
-
if (
|
|
8279
|
+
const handoffHistoryPath = join18(cwd, HANDOFF_HISTORY_PATH);
|
|
8280
|
+
if (existsSync18(handoffHistoryPath)) {
|
|
8762
8281
|
const count = lineCount(readFileSync7(handoffHistoryPath, "utf-8"));
|
|
8763
8282
|
if (count > 0) {
|
|
8764
|
-
console.log(
|
|
8283
|
+
console.log(chalk15.dim(` Handoff entries: ${count}`));
|
|
8765
8284
|
}
|
|
8766
8285
|
}
|
|
8767
|
-
const completedPath =
|
|
8768
|
-
if (
|
|
8286
|
+
const completedPath = join18(cwd, COMPLETED_TASKS_PATH);
|
|
8287
|
+
if (existsSync18(completedPath)) {
|
|
8769
8288
|
const count = lineCount(readFileSync7(completedPath, "utf-8"));
|
|
8770
8289
|
if (count > 0) {
|
|
8771
|
-
console.log(
|
|
8290
|
+
console.log(chalk15.dim(` Completed tasks archived: ${count}`));
|
|
8772
8291
|
}
|
|
8773
8292
|
}
|
|
8774
8293
|
console.log("");
|
|
@@ -8779,7 +8298,7 @@ function createGovernanceCommand() {
|
|
|
8779
8298
|
const store = new GovernanceStore(cwd);
|
|
8780
8299
|
const archInfo = resolveArchitecturePath2(cwd);
|
|
8781
8300
|
if (!archInfo.path) {
|
|
8782
|
-
console.log(
|
|
8301
|
+
console.log(chalk15.yellow("No architecture file found."));
|
|
8783
8302
|
return;
|
|
8784
8303
|
}
|
|
8785
8304
|
if (options.raw) {
|
|
@@ -8790,11 +8309,11 @@ function createGovernanceCommand() {
|
|
|
8790
8309
|
if (archInfo.source === "agd") {
|
|
8791
8310
|
const result = await store.readArchitecture();
|
|
8792
8311
|
if (!result.ok) {
|
|
8793
|
-
console.log(
|
|
8312
|
+
console.log(chalk15.red(`Failed to read architecture: ${result.error}`));
|
|
8794
8313
|
return;
|
|
8795
8314
|
}
|
|
8796
8315
|
if (!result.value) {
|
|
8797
|
-
console.log(
|
|
8316
|
+
console.log(chalk15.yellow("Architecture file is empty."));
|
|
8798
8317
|
return;
|
|
8799
8318
|
}
|
|
8800
8319
|
console.log(result.value);
|
|
@@ -8804,7 +8323,7 @@ function createGovernanceCommand() {
|
|
|
8804
8323
|
const legacyParsed = matter4(legacyRaw);
|
|
8805
8324
|
const legacyContent = legacyParsed.content.trim();
|
|
8806
8325
|
if (!legacyContent) {
|
|
8807
|
-
console.log(
|
|
8326
|
+
console.log(chalk15.yellow("Architecture file is empty."));
|
|
8808
8327
|
return;
|
|
8809
8328
|
}
|
|
8810
8329
|
console.log(legacyContent);
|
|
@@ -8812,33 +8331,33 @@ function createGovernanceCommand() {
|
|
|
8812
8331
|
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) => {
|
|
8813
8332
|
const cwd = process.cwd();
|
|
8814
8333
|
const filePath = options.file;
|
|
8815
|
-
if (!
|
|
8816
|
-
console.log(
|
|
8334
|
+
if (!existsSync18(filePath)) {
|
|
8335
|
+
console.log(chalk15.red(`File not found: ${filePath}`));
|
|
8817
8336
|
process.exit(1);
|
|
8818
8337
|
}
|
|
8819
|
-
const content = await
|
|
8338
|
+
const content = await readFile10(filePath, "utf-8");
|
|
8820
8339
|
const store = new GovernanceStore(cwd);
|
|
8821
8340
|
const result = await store.updateArchitecture(content, options.reason, options.by);
|
|
8822
8341
|
if (!result.ok) {
|
|
8823
|
-
console.log(
|
|
8342
|
+
console.log(chalk15.red(`Failed to update architecture: ${result.error}`));
|
|
8824
8343
|
process.exit(1);
|
|
8825
8344
|
}
|
|
8826
|
-
console.log(
|
|
8345
|
+
console.log(chalk15.green("\u2713 Architecture updated"));
|
|
8827
8346
|
});
|
|
8828
8347
|
const tasks = governance.command("task").description("Update tasks in governance store");
|
|
8829
8348
|
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) => {
|
|
8830
8349
|
const status2 = options.status;
|
|
8831
8350
|
if (!isTaskStatus(status2)) {
|
|
8832
|
-
console.log(
|
|
8351
|
+
console.log(chalk15.red(`Invalid status: ${options.status}`));
|
|
8833
8352
|
process.exit(1);
|
|
8834
8353
|
}
|
|
8835
8354
|
const store = new GovernanceStore(process.cwd());
|
|
8836
8355
|
const result = await store.updateTask(taskId, status2, options.notes);
|
|
8837
8356
|
if (!result.ok) {
|
|
8838
|
-
console.log(
|
|
8357
|
+
console.log(chalk15.red(`Failed to update task: ${result.error}`));
|
|
8839
8358
|
process.exit(1);
|
|
8840
8359
|
}
|
|
8841
|
-
console.log(
|
|
8360
|
+
console.log(chalk15.green(`\u2713 Task ${taskId} updated to ${status2}`));
|
|
8842
8361
|
});
|
|
8843
8362
|
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) => {
|
|
8844
8363
|
const store = new GovernanceStore(process.cwd());
|
|
@@ -8851,10 +8370,10 @@ function createGovernanceCommand() {
|
|
|
8851
8370
|
};
|
|
8852
8371
|
const result = await store.logHandoff(entry);
|
|
8853
8372
|
if (!result.ok) {
|
|
8854
|
-
console.log(
|
|
8373
|
+
console.log(chalk15.red(`Failed to log handoff: ${result.error}`));
|
|
8855
8374
|
process.exit(1);
|
|
8856
8375
|
}
|
|
8857
|
-
console.log(
|
|
8376
|
+
console.log(chalk15.green("\u2713 Handoff logged"));
|
|
8858
8377
|
});
|
|
8859
8378
|
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) => {
|
|
8860
8379
|
const result = await migrateLegacyGovernance({
|
|
@@ -8863,23 +8382,23 @@ function createGovernanceCommand() {
|
|
|
8863
8382
|
dryRun: options.dryRun,
|
|
8864
8383
|
updatedBy: options.by
|
|
8865
8384
|
});
|
|
8866
|
-
console.log(
|
|
8385
|
+
console.log(chalk15.bold("\nMigration Summary"));
|
|
8867
8386
|
console.log(
|
|
8868
|
-
result.migratedArchitecture ?
|
|
8387
|
+
result.migratedArchitecture ? chalk15.green(" \u2713 Architecture migrated") : chalk15.dim(" \u25CB Architecture migration skipped")
|
|
8869
8388
|
);
|
|
8870
8389
|
console.log(
|
|
8871
|
-
result.migratedTasks ?
|
|
8390
|
+
result.migratedTasks ? chalk15.green(" \u2713 Tasks migrated") : chalk15.dim(" \u25CB Tasks migration skipped")
|
|
8872
8391
|
);
|
|
8873
8392
|
if (result.archivedLegacyFiles.length > 0) {
|
|
8874
|
-
console.log(
|
|
8393
|
+
console.log(chalk15.dim(" Archived legacy files:"));
|
|
8875
8394
|
for (const file of result.archivedLegacyFiles) {
|
|
8876
|
-
console.log(
|
|
8395
|
+
console.log(chalk15.dim(` - ${file}`));
|
|
8877
8396
|
}
|
|
8878
8397
|
}
|
|
8879
8398
|
if (result.warnings.length > 0) {
|
|
8880
|
-
console.log(
|
|
8399
|
+
console.log(chalk15.yellow("\nWarnings:"));
|
|
8881
8400
|
for (const warning of result.warnings) {
|
|
8882
|
-
console.log(
|
|
8401
|
+
console.log(chalk15.yellow(` - ${warning}`));
|
|
8883
8402
|
}
|
|
8884
8403
|
}
|
|
8885
8404
|
console.log("");
|
|
@@ -8890,13 +8409,13 @@ function createGovernanceCommand() {
|
|
|
8890
8409
|
view.init(cwd);
|
|
8891
8410
|
await view.loadFromDisk(cwd);
|
|
8892
8411
|
view.close();
|
|
8893
|
-
console.log(
|
|
8412
|
+
console.log(chalk15.green("\u2713 Governance SQLite DB initialized"));
|
|
8894
8413
|
});
|
|
8895
8414
|
return governance;
|
|
8896
8415
|
}
|
|
8897
8416
|
|
|
8898
8417
|
// src/cli/qa.ts
|
|
8899
|
-
import
|
|
8418
|
+
import chalk16 from "chalk";
|
|
8900
8419
|
|
|
8901
8420
|
// src/core/browser/health.ts
|
|
8902
8421
|
function isPlaywrightAvailable() {
|
|
@@ -8996,19 +8515,19 @@ async function runBrowserHealthCheck(url, pages = ["/"], _options) {
|
|
|
8996
8515
|
}
|
|
8997
8516
|
|
|
8998
8517
|
// src/core/browser/diff-aware.ts
|
|
8999
|
-
import { existsSync as
|
|
9000
|
-
import { join as
|
|
8518
|
+
import { existsSync as existsSync19 } from "fs";
|
|
8519
|
+
import { join as join19 } from "path";
|
|
9001
8520
|
function detectFramework(cwd) {
|
|
9002
|
-
if (
|
|
8521
|
+
if (existsSync19(join19(cwd, "astro.config.mjs")) || existsSync19(join19(cwd, "astro.config.ts"))) {
|
|
9003
8522
|
return "astro";
|
|
9004
8523
|
}
|
|
9005
|
-
if (
|
|
8524
|
+
if (existsSync19(join19(cwd, "next.config.js")) || existsSync19(join19(cwd, "next.config.mjs")) || existsSync19(join19(cwd, "next.config.ts"))) {
|
|
9006
8525
|
return "next";
|
|
9007
8526
|
}
|
|
9008
|
-
if (
|
|
8527
|
+
if (existsSync19(join19(cwd, "remix.config.js")) || existsSync19(join19(cwd, "remix.config.ts"))) {
|
|
9009
8528
|
return "remix";
|
|
9010
8529
|
}
|
|
9011
|
-
if (
|
|
8530
|
+
if (existsSync19(join19(cwd, "vite.config.ts")) || existsSync19(join19(cwd, "vite.config.js"))) {
|
|
9012
8531
|
return "vite";
|
|
9013
8532
|
}
|
|
9014
8533
|
return "unknown";
|
|
@@ -9018,43 +8537,43 @@ function detectFramework(cwd) {
|
|
|
9018
8537
|
async function qa(options = {}) {
|
|
9019
8538
|
const cwd = process.cwd();
|
|
9020
8539
|
if (!isPlaywrightAvailable()) {
|
|
9021
|
-
console.log(
|
|
9022
|
-
console.log(
|
|
9023
|
-
console.log(
|
|
8540
|
+
console.log(chalk16.yellow("Playwright is not installed."));
|
|
8541
|
+
console.log(chalk16.dim("Install it with: npm install playwright-core"));
|
|
8542
|
+
console.log(chalk16.dim("Then run: npx playwright install chromium"));
|
|
9024
8543
|
return;
|
|
9025
8544
|
}
|
|
9026
8545
|
const url = options.url ?? "http://localhost:3000";
|
|
9027
8546
|
const framework = detectFramework(cwd);
|
|
9028
8547
|
console.log();
|
|
9029
|
-
console.log(
|
|
8548
|
+
console.log(chalk16.bold("Visual QA"));
|
|
9030
8549
|
if (framework !== "unknown") {
|
|
9031
|
-
console.log(
|
|
8550
|
+
console.log(chalk16.dim(`Detected framework: ${framework}`));
|
|
9032
8551
|
}
|
|
9033
8552
|
const pages = options.pages ?? ["/"];
|
|
9034
|
-
console.log(
|
|
8553
|
+
console.log(chalk16.dim(`Testing ${pages.length} page(s) on ${url}...`));
|
|
9035
8554
|
console.log();
|
|
9036
8555
|
const report = await runBrowserHealthCheck(url, pages, options);
|
|
9037
|
-
console.log(
|
|
8556
|
+
console.log(chalk16.bold(`Overall: ${report.overallScore}/100 (${report.overallLabel})`));
|
|
9038
8557
|
console.log();
|
|
9039
8558
|
for (const page of report.pages) {
|
|
9040
|
-
const color = page.overallScore >= 75 ?
|
|
9041
|
-
console.log(` ${page.route.padEnd(20)} ${color(`${page.overallScore}/100`)} ${page.errors.length > 0 ?
|
|
8559
|
+
const color = page.overallScore >= 75 ? chalk16.green : page.overallScore >= 50 ? chalk16.yellow : chalk16.red;
|
|
8560
|
+
console.log(` ${page.route.padEnd(20)} ${color(`${page.overallScore}/100`)} ${page.errors.length > 0 ? chalk16.red(`\u2014 ${page.errors[0]}`) : chalk16.dim("\u2014 clean")}`);
|
|
9042
8561
|
}
|
|
9043
8562
|
if (report.screenshotDir) {
|
|
9044
|
-
console.log(
|
|
8563
|
+
console.log(chalk16.dim(`
|
|
9045
8564
|
Screenshots: ${report.screenshotDir}`));
|
|
9046
8565
|
}
|
|
9047
|
-
console.log(
|
|
8566
|
+
console.log(chalk16.dim("\nPowered by gstack-inspired automation."));
|
|
9048
8567
|
}
|
|
9049
8568
|
|
|
9050
8569
|
// src/cli/retro.ts
|
|
9051
|
-
import
|
|
8570
|
+
import chalk17 from "chalk";
|
|
9052
8571
|
|
|
9053
8572
|
// src/core/metrics/session.ts
|
|
9054
|
-
import { readdirSync as readdirSync4, readFileSync as readFileSync8, existsSync as
|
|
9055
|
-
import { join as
|
|
8573
|
+
import { readdirSync as readdirSync4, readFileSync as readFileSync8, existsSync as existsSync20 } from "fs";
|
|
8574
|
+
import { join as join20 } from "path";
|
|
9056
8575
|
function computeSessionMetrics(cwd) {
|
|
9057
|
-
const atomsDir =
|
|
8576
|
+
const atomsDir = join20(cwd, ".archon", "atoms");
|
|
9058
8577
|
let atomsCompleted = 0;
|
|
9059
8578
|
let atomsFailed = 0;
|
|
9060
8579
|
let atomsBlocked = 0;
|
|
@@ -9066,7 +8585,7 @@ function computeSessionMetrics(cwd) {
|
|
|
9066
8585
|
const fileHits = {};
|
|
9067
8586
|
let earliestTime = null;
|
|
9068
8587
|
let latestTime = null;
|
|
9069
|
-
if (!
|
|
8588
|
+
if (!existsSync20(atomsDir)) {
|
|
9070
8589
|
return {
|
|
9071
8590
|
duration: "0m",
|
|
9072
8591
|
atomsCompleted: 0,
|
|
@@ -9082,7 +8601,7 @@ function computeSessionMetrics(cwd) {
|
|
|
9082
8601
|
const files = readdirSync4(atomsDir).filter((f) => f.endsWith(".json"));
|
|
9083
8602
|
for (const file of files) {
|
|
9084
8603
|
try {
|
|
9085
|
-
const content = readFileSync8(
|
|
8604
|
+
const content = readFileSync8(join20(atomsDir, file), "utf-8");
|
|
9086
8605
|
const atom = JSON.parse(content);
|
|
9087
8606
|
switch (atom.status) {
|
|
9088
8607
|
case "DONE":
|
|
@@ -9147,30 +8666,30 @@ async function retro() {
|
|
|
9147
8666
|
const cwd = process.cwd();
|
|
9148
8667
|
const metrics = computeSessionMetrics(cwd);
|
|
9149
8668
|
console.log();
|
|
9150
|
-
console.log(
|
|
9151
|
-
console.log(
|
|
8669
|
+
console.log(chalk17.bold("Session Retrospective"));
|
|
8670
|
+
console.log(chalk17.dim("\u2550".repeat(40)));
|
|
9152
8671
|
console.log(` Duration: ${metrics.duration}`);
|
|
9153
|
-
console.log(` Atoms: ${
|
|
8672
|
+
console.log(` Atoms: ${chalk17.green(`${metrics.atomsCompleted} completed`)}, ${metrics.atomsFailed > 0 ? chalk17.red(`${metrics.atomsFailed} failed`) : `${metrics.atomsFailed} failed`}, ${metrics.atomsBlocked} blocked`);
|
|
9154
8673
|
console.log(` Gate pass: ${metrics.gatePassRate}% (${metrics.gatePassCount}/${metrics.gateTotalCount})`);
|
|
9155
8674
|
console.log(` Risk avg: ${metrics.averageRiskScore}/100`);
|
|
9156
8675
|
if (metrics.topFailureGate) {
|
|
9157
|
-
console.log(` Top failure: ${
|
|
8676
|
+
console.log(` Top failure: ${chalk17.yellow(metrics.topFailureGate)}`);
|
|
9158
8677
|
}
|
|
9159
8678
|
if (metrics.fileHotspot) {
|
|
9160
|
-
console.log(` Hotspot: ${
|
|
8679
|
+
console.log(` Hotspot: ${chalk17.cyan(metrics.fileHotspot.file)} (${metrics.fileHotspot.atomCount} atoms)`);
|
|
9161
8680
|
}
|
|
9162
8681
|
console.log();
|
|
9163
|
-
console.log(
|
|
8682
|
+
console.log(chalk17.dim("Powered by gstack-inspired automation."));
|
|
9164
8683
|
}
|
|
9165
8684
|
|
|
9166
8685
|
// src/cli/index.ts
|
|
9167
|
-
var program = new
|
|
8686
|
+
var program = new Command4();
|
|
9168
8687
|
enableTerminalCompatibilityMode();
|
|
9169
8688
|
program.name("archon").description("Local-first AI-powered development governance").version(getCurrentVersion()).action(async () => {
|
|
9170
8689
|
const cwd = process.cwd();
|
|
9171
8690
|
const wasInitialized = isInitialized(cwd);
|
|
9172
8691
|
if (!wasInitialized) {
|
|
9173
|
-
console.log(
|
|
8692
|
+
console.log(chalk18.blue("\nArchonDev is not initialized in this folder.\n"));
|
|
9174
8693
|
await init({ analyze: true, git: true });
|
|
9175
8694
|
}
|
|
9176
8695
|
await start({ skipGovernanceBanner: !wasInitialized });
|
|
@@ -9178,7 +8697,7 @@ program.name("archon").description("Local-first AI-powered development governanc
|
|
|
9178
8697
|
program.command("login", { hidden: true }).description("Authenticate with ArchonDev").option("-p, --provider <provider>", "OAuth provider (github or google)", "github").action(async (options) => {
|
|
9179
8698
|
const provider = options.provider;
|
|
9180
8699
|
if (provider !== "github" && provider !== "google") {
|
|
9181
|
-
console.error(
|
|
8700
|
+
console.error(chalk18.red('Invalid provider. Use "github" or "google"'));
|
|
9182
8701
|
process.exit(1);
|
|
9183
8702
|
}
|
|
9184
8703
|
await login(provider);
|
|
@@ -9190,20 +8709,20 @@ program.command("status").description("Show local mode, auth, and project status
|
|
|
9190
8709
|
await status();
|
|
9191
8710
|
});
|
|
9192
8711
|
program.command("mode").description("Choose local governance mode or BYOK AI mode").action(async () => {
|
|
9193
|
-
const { showUpgradeMenu } = await import("./tier-selection-
|
|
8712
|
+
const { showUpgradeMenu } = await import("./tier-selection-5KPN2RF2.js");
|
|
9194
8713
|
await showUpgradeMenu();
|
|
9195
8714
|
});
|
|
9196
8715
|
program.command("upgrade", { hidden: true }).action(async () => {
|
|
9197
|
-
const { showUpgradeMenu } = await import("./tier-selection-
|
|
8716
|
+
const { showUpgradeMenu } = await import("./tier-selection-5KPN2RF2.js");
|
|
9198
8717
|
await showUpgradeMenu();
|
|
9199
8718
|
});
|
|
9200
8719
|
program.command("pricing", { hidden: true }).action(async () => {
|
|
9201
|
-
const { showUpgradeMenu } = await import("./tier-selection-
|
|
8720
|
+
const { showUpgradeMenu } = await import("./tier-selection-5KPN2RF2.js");
|
|
9202
8721
|
await showUpgradeMenu();
|
|
9203
8722
|
});
|
|
9204
8723
|
var configCommand = program.command("config").description("Configuration commands");
|
|
9205
8724
|
configCommand.command("ai").description("Run guided BYOK AI provider setup").action(async () => {
|
|
9206
|
-
const { runGuidedAIConfig } = await import("./tier-selection-
|
|
8725
|
+
const { runGuidedAIConfig } = await import("./tier-selection-5KPN2RF2.js");
|
|
9207
8726
|
await runGuidedAIConfig();
|
|
9208
8727
|
});
|
|
9209
8728
|
program.command("init").description("Initialize ArchonDev in current project").option("--analyze", "Run enhanced analysis of codebase").option("--no-git", "Skip git initialization").action(async (options) => {
|
|
@@ -9331,6 +8850,8 @@ a11yCommand.action(async () => {
|
|
|
9331
8850
|
});
|
|
9332
8851
|
program.addCommand(createSeoCommand());
|
|
9333
8852
|
program.addCommand(createGeoCommand());
|
|
8853
|
+
program.addCommand(createTruthLayerCommand());
|
|
8854
|
+
program.addCommand(createBrandCommand());
|
|
9334
8855
|
program.command("deploy").description("Deploy application (auto-detects platform)").option("-p, --platform <name>", "Specify platform (fly/vercel/netlify/railway/render)").option("--preview", "Deploy to preview/staging environment").option("--dry-run", "Show what would happen without deploying").action(deploy);
|
|
9335
8856
|
var indexCmd = program.command("index").description("Semantic codebase indexing (local Ollama or cloud pgvector)");
|
|
9336
8857
|
indexCmd.command("init").description("Initialize semantic index").option("--local", "Use local Ollama for embeddings (default)").addOption(new Option("--cloud", "Use cloud pgvector with OpenAI embeddings").hideHelp()).action(indexInit);
|
|
@@ -9370,7 +8891,7 @@ cleanupCmd.command("check").description("Analyze workspace for bloat and mainten
|
|
|
9370
8891
|
cleanupCmd.command("run").description("Execute cleanup (archive old entries, remove stale files)").action(cleanupRun);
|
|
9371
8892
|
cleanupCmd.command("auto").description("Enable/disable automatic cleanup checks").argument("[action]", "enable, disable, or status", "status").action(async (action) => {
|
|
9372
8893
|
if (action !== "enable" && action !== "disable" && action !== "status") {
|
|
9373
|
-
console.error(
|
|
8894
|
+
console.error(chalk18.red("Invalid action. Use: enable, disable, or status"));
|
|
9374
8895
|
process.exit(1);
|
|
9375
8896
|
}
|
|
9376
8897
|
await cleanupAuto(action);
|