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/chunk-CFJECC3B.js
DELETED
|
@@ -1,495 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
recordWebCheckResult
|
|
3
|
-
} from "./chunk-3ASILTFB.js";
|
|
4
|
-
import {
|
|
5
|
-
ArchitectAgent
|
|
6
|
-
} from "./chunk-D3TVDCJA.js";
|
|
7
|
-
import {
|
|
8
|
-
loadConfig
|
|
9
|
-
} from "./chunk-GGRW4NTA.js";
|
|
10
|
-
|
|
11
|
-
// src/cli/geo.ts
|
|
12
|
-
import { Command } from "commander";
|
|
13
|
-
import chalk from "chalk";
|
|
14
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
15
|
-
import { existsSync } from "fs";
|
|
16
|
-
import { join } from "path";
|
|
17
|
-
import { createInterface } from "readline";
|
|
18
|
-
import { glob } from "glob";
|
|
19
|
-
import * as yaml from "yaml";
|
|
20
|
-
var CONFIG_PATH = ".archon/config.yaml";
|
|
21
|
-
function createPrompt() {
|
|
22
|
-
const rl = createInterface({
|
|
23
|
-
input: process.stdin,
|
|
24
|
-
output: process.stdout
|
|
25
|
-
});
|
|
26
|
-
return {
|
|
27
|
-
ask: (question) => new Promise((resolve) => {
|
|
28
|
-
rl.question(question, resolve);
|
|
29
|
-
}),
|
|
30
|
-
close: () => rl.close()
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
async function loadGeoConfig(cwd) {
|
|
34
|
-
const configPath = join(cwd, CONFIG_PATH);
|
|
35
|
-
if (!existsSync(configPath)) {
|
|
36
|
-
return {};
|
|
37
|
-
}
|
|
38
|
-
try {
|
|
39
|
-
const content = await readFile(configPath, "utf-8");
|
|
40
|
-
return yaml.parse(content);
|
|
41
|
-
} catch {
|
|
42
|
-
return {};
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
async function saveGeoConfig(cwd, config) {
|
|
46
|
-
const configPath = join(cwd, CONFIG_PATH);
|
|
47
|
-
const archonDir = join(cwd, ".archon");
|
|
48
|
-
if (!existsSync(archonDir)) {
|
|
49
|
-
await mkdir(archonDir, { recursive: true });
|
|
50
|
-
}
|
|
51
|
-
let existing = {};
|
|
52
|
-
if (existsSync(configPath)) {
|
|
53
|
-
try {
|
|
54
|
-
const content = await readFile(configPath, "utf-8");
|
|
55
|
-
existing = yaml.parse(content);
|
|
56
|
-
} catch {
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
const merged = { ...existing, ...config };
|
|
60
|
-
await writeFile(configPath, yaml.stringify(merged), "utf-8");
|
|
61
|
-
}
|
|
62
|
-
async function readPageContent(patterns) {
|
|
63
|
-
const cwd = process.cwd();
|
|
64
|
-
let content = "";
|
|
65
|
-
for (const pattern of patterns) {
|
|
66
|
-
const files = await glob(pattern, { cwd, ignore: ["**/node_modules/**", "**/dist/**"] });
|
|
67
|
-
for (const file of files.slice(0, 3)) {
|
|
68
|
-
try {
|
|
69
|
-
const fileContent = await readFile(join(cwd, file), "utf-8");
|
|
70
|
-
content += `
|
|
71
|
-
--- File: ${file} ---
|
|
72
|
-
${fileContent.slice(0, 5e3)}
|
|
73
|
-
`;
|
|
74
|
-
} catch {
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return content || "No content found.";
|
|
79
|
-
}
|
|
80
|
-
async function checkStrongModelAccess() {
|
|
81
|
-
const config = await loadConfig();
|
|
82
|
-
const tier = config.tier ?? "FREE";
|
|
83
|
-
if (tier === "CREDITS" || tier === "BYOK") {
|
|
84
|
-
return { allowed: true, tier };
|
|
85
|
-
}
|
|
86
|
-
return { allowed: false, tier };
|
|
87
|
-
}
|
|
88
|
-
var IDENTITY_SYSTEM_PROMPT = `You are a brand strategist and SEO expert. Your job is to create concise, memorable brand identity phrases and descriptions.
|
|
89
|
-
|
|
90
|
-
Guidelines:
|
|
91
|
-
- Identity phrases should be EXACTLY 7 words
|
|
92
|
-
- Identity phrases should be unique, memorable, and capture the essence of the brand
|
|
93
|
-
- Short descriptions should be EXACTLY 50 words
|
|
94
|
-
- Descriptions should explain what the product/service does and why it matters
|
|
95
|
-
- Both should be optimized for search engines and AI assistants (GEO)
|
|
96
|
-
- Avoid jargon unless it's industry-standard terminology
|
|
97
|
-
- Focus on value proposition and differentiation
|
|
98
|
-
|
|
99
|
-
Output your response as valid JSON.`;
|
|
100
|
-
async function generateIdentityCandidates(pageContent) {
|
|
101
|
-
const agent = new ArchitectAgent({ temperature: 0.8 });
|
|
102
|
-
const prompt = `Based on the following website content, generate brand identity options.
|
|
103
|
-
|
|
104
|
-
${pageContent}
|
|
105
|
-
|
|
106
|
-
Generate EXACTLY 3 candidate 7-word brand phrases and 3 candidate 50-word descriptions.
|
|
107
|
-
|
|
108
|
-
Output as JSON:
|
|
109
|
-
{
|
|
110
|
-
"phrases": [
|
|
111
|
-
{ "phrase": "exactly seven words go right here", "rationale": "why this phrase works" },
|
|
112
|
-
{ "phrase": "another seven word phrase goes here", "rationale": "why this phrase works" },
|
|
113
|
-
{ "phrase": "third seven word phrase goes here", "rationale": "why this phrase works" }
|
|
114
|
-
],
|
|
115
|
-
"descriptions": [
|
|
116
|
-
{ "description": "exactly 50 words description...", "rationale": "why this works" },
|
|
117
|
-
{ "description": "another 50 words description...", "rationale": "why this works" },
|
|
118
|
-
{ "description": "third 50 words description...", "rationale": "why this works" }
|
|
119
|
-
]
|
|
120
|
-
}`;
|
|
121
|
-
const response = await agent.client.chat(
|
|
122
|
-
IDENTITY_SYSTEM_PROMPT,
|
|
123
|
-
prompt,
|
|
124
|
-
{ temperature: 0.8, maxTokens: 2e3 }
|
|
125
|
-
);
|
|
126
|
-
const jsonMatch = response.content.match(/\{[\s\S]*\}/);
|
|
127
|
-
if (!jsonMatch) {
|
|
128
|
-
throw new Error("Failed to parse AI response");
|
|
129
|
-
}
|
|
130
|
-
const parsed = JSON.parse(jsonMatch[0]);
|
|
131
|
-
return parsed;
|
|
132
|
-
}
|
|
133
|
-
async function geoIdentity() {
|
|
134
|
-
const cwd = process.cwd();
|
|
135
|
-
const prompt = createPrompt();
|
|
136
|
-
try {
|
|
137
|
-
console.log(chalk.blue("\n\u{1F3AF} GEO Identity Generator\n"));
|
|
138
|
-
const { allowed, tier } = await checkStrongModelAccess();
|
|
139
|
-
if (!allowed) {
|
|
140
|
-
console.log(chalk.yellow(`[!] Your tier (${tier}) uses basic models.`));
|
|
141
|
-
console.log(chalk.dim("For better results, add credits or use BYOK mode.\n"));
|
|
142
|
-
}
|
|
143
|
-
console.log(chalk.dim("Reading homepage and about page content...\n"));
|
|
144
|
-
const pageContent = await readPageContent([
|
|
145
|
-
"**/index.html",
|
|
146
|
-
"**/index.{jsx,tsx,astro,svelte,vue}",
|
|
147
|
-
"**/about.{html,jsx,tsx,astro,svelte,vue,md}",
|
|
148
|
-
"**/about/index.{jsx,tsx,astro,svelte,vue}",
|
|
149
|
-
"**/pages/index.{jsx,tsx,astro,svelte,vue}",
|
|
150
|
-
"**/app/page.{jsx,tsx}",
|
|
151
|
-
"README.md"
|
|
152
|
-
]);
|
|
153
|
-
if (pageContent === "No content found.") {
|
|
154
|
-
console.log(chalk.yellow("No homepage or about page content found."));
|
|
155
|
-
console.log(chalk.dim("Create an index file or README.md first.\n"));
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
console.log(chalk.dim("Generating identity candidates with AI...\n"));
|
|
159
|
-
const candidates = await generateIdentityCandidates(pageContent);
|
|
160
|
-
console.log(chalk.bold("\u{1F4CC} 7-Word Brand Phrases:\n"));
|
|
161
|
-
candidates.phrases.forEach((p, i) => {
|
|
162
|
-
console.log(` ${chalk.cyan(`${i + 1})`)} ${chalk.bold(p.phrase)}`);
|
|
163
|
-
console.log(` ${chalk.dim(p.rationale)}
|
|
164
|
-
`);
|
|
165
|
-
});
|
|
166
|
-
const phraseChoice = await prompt.ask('Select a phrase (1-3) or "r" to regenerate: ');
|
|
167
|
-
if (phraseChoice.toLowerCase() === "r") {
|
|
168
|
-
console.log(chalk.dim("\nRegenerating... Run the command again.\n"));
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
const phraseIndex = parseInt(phraseChoice, 10) - 1;
|
|
172
|
-
const selectedPhrase = candidates.phrases[phraseIndex];
|
|
173
|
-
if (isNaN(phraseIndex) || phraseIndex < 0 || phraseIndex >= candidates.phrases.length || !selectedPhrase) {
|
|
174
|
-
console.log(chalk.red("Invalid selection."));
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
177
|
-
console.log(chalk.bold("\n\u{1F4DD} 50-Word Descriptions:\n"));
|
|
178
|
-
candidates.descriptions.forEach((d, i) => {
|
|
179
|
-
console.log(` ${chalk.cyan(`${i + 1})`)} ${d.description}`);
|
|
180
|
-
console.log(` ${chalk.dim(d.rationale)}
|
|
181
|
-
`);
|
|
182
|
-
});
|
|
183
|
-
const descChoice = await prompt.ask('Select a description (1-3) or "r" to regenerate: ');
|
|
184
|
-
if (descChoice.toLowerCase() === "r") {
|
|
185
|
-
console.log(chalk.dim("\nRegenerating... Run the command again.\n"));
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
const descIndex = parseInt(descChoice, 10) - 1;
|
|
189
|
-
const selectedDescription = candidates.descriptions[descIndex];
|
|
190
|
-
if (isNaN(descIndex) || descIndex < 0 || descIndex >= candidates.descriptions.length || !selectedDescription) {
|
|
191
|
-
console.log(chalk.red("Invalid selection."));
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
const geoConfig = {
|
|
195
|
-
geo: {
|
|
196
|
-
identityPhrase: selectedPhrase.phrase,
|
|
197
|
-
shortDescription: selectedDescription.description,
|
|
198
|
-
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
199
|
-
}
|
|
200
|
-
};
|
|
201
|
-
await saveGeoConfig(cwd, geoConfig);
|
|
202
|
-
console.log(chalk.green("\n\u2705 Identity saved!\n"));
|
|
203
|
-
console.log(chalk.dim(` Phrase: ${selectedPhrase.phrase}`));
|
|
204
|
-
console.log(chalk.dim(` Description: ${selectedDescription.description.slice(0, 60)}...`));
|
|
205
|
-
console.log();
|
|
206
|
-
console.log(chalk.cyan(`Use 'archon geo schema' to generate JSON-LD.`));
|
|
207
|
-
} finally {
|
|
208
|
-
prompt.close();
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
async function geoSchema(options) {
|
|
212
|
-
const cwd = process.cwd();
|
|
213
|
-
console.log(chalk.blue("\n\u{1F4E6} JSON-LD Schema Generator\n"));
|
|
214
|
-
const config = await loadGeoConfig(cwd);
|
|
215
|
-
if (!config.geo?.identityPhrase || !config.geo?.shortDescription) {
|
|
216
|
-
console.log(chalk.yellow("No identity defined."));
|
|
217
|
-
console.log(chalk.dim(`Run 'archon geo identity' first.
|
|
218
|
-
`));
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
const { identityPhrase, shortDescription } = config.geo;
|
|
222
|
-
let orgName = identityPhrase.split(" ").slice(0, 2).join(" ");
|
|
223
|
-
try {
|
|
224
|
-
const pkgPath = join(cwd, "package.json");
|
|
225
|
-
if (existsSync(pkgPath)) {
|
|
226
|
-
const pkg = JSON.parse(await readFile(pkgPath, "utf-8"));
|
|
227
|
-
if (pkg.name) {
|
|
228
|
-
orgName = pkg.name.replace(/-/g, " ").replace(/^\w/, (c) => c.toUpperCase());
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
} catch {
|
|
232
|
-
}
|
|
233
|
-
const schema = {
|
|
234
|
-
"@context": "https://schema.org",
|
|
235
|
-
"@graph": [
|
|
236
|
-
{
|
|
237
|
-
"@type": "Organization",
|
|
238
|
-
"@id": "#organization",
|
|
239
|
-
name: orgName,
|
|
240
|
-
description: shortDescription,
|
|
241
|
-
slogan: identityPhrase
|
|
242
|
-
},
|
|
243
|
-
{
|
|
244
|
-
"@type": "WebSite",
|
|
245
|
-
"@id": "#website",
|
|
246
|
-
name: orgName,
|
|
247
|
-
description: shortDescription,
|
|
248
|
-
publisher: { "@id": "#organization" }
|
|
249
|
-
},
|
|
250
|
-
{
|
|
251
|
-
"@type": "Service",
|
|
252
|
-
name: orgName,
|
|
253
|
-
description: shortDescription,
|
|
254
|
-
provider: { "@id": "#organization" }
|
|
255
|
-
}
|
|
256
|
-
]
|
|
257
|
-
};
|
|
258
|
-
const jsonLd = JSON.stringify(schema, null, 2);
|
|
259
|
-
if (options.output) {
|
|
260
|
-
await writeFile(options.output, jsonLd, "utf-8");
|
|
261
|
-
console.log(chalk.green(`\u2705 Schema written to ${options.output}`));
|
|
262
|
-
} else {
|
|
263
|
-
console.log(chalk.bold("Generated JSON-LD:\n"));
|
|
264
|
-
console.log(chalk.cyan(jsonLd));
|
|
265
|
-
}
|
|
266
|
-
if (options.apply) {
|
|
267
|
-
console.log(chalk.dim("\nAttempting to insert into homepage <head>...\n"));
|
|
268
|
-
const indexFiles = await glob("**/index.html", { cwd, ignore: ["**/node_modules/**", "**/dist/**"] });
|
|
269
|
-
if (indexFiles.length === 0) {
|
|
270
|
-
console.log(chalk.yellow("No index.html found. Manually add to your HTML <head>:"));
|
|
271
|
-
console.log(chalk.dim(`<script type="application/ld+json">
|
|
272
|
-
${jsonLd}
|
|
273
|
-
</script>`));
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
const firstIndexFile = indexFiles[0];
|
|
277
|
-
if (!firstIndexFile) {
|
|
278
|
-
console.log(chalk.yellow("No index.html found."));
|
|
279
|
-
return;
|
|
280
|
-
}
|
|
281
|
-
const indexPath = join(cwd, firstIndexFile);
|
|
282
|
-
let indexContent = await readFile(indexPath, "utf-8");
|
|
283
|
-
const scriptTag = `<script type="application/ld+json">
|
|
284
|
-
${jsonLd}
|
|
285
|
-
</script>`;
|
|
286
|
-
if (indexContent.includes("application/ld+json")) {
|
|
287
|
-
console.log(chalk.yellow("JSON-LD already exists in index.html. Remove it first or update manually."));
|
|
288
|
-
return;
|
|
289
|
-
}
|
|
290
|
-
indexContent = indexContent.replace("</head>", `${scriptTag}
|
|
291
|
-
</head>`);
|
|
292
|
-
await writeFile(indexPath, indexContent, "utf-8");
|
|
293
|
-
console.log(chalk.green(`\u2705 JSON-LD inserted into ${firstIndexFile}`));
|
|
294
|
-
}
|
|
295
|
-
console.log();
|
|
296
|
-
}
|
|
297
|
-
var FAQ_SYSTEM_PROMPT = `You are an SEO expert creating FAQ content for schema markup.
|
|
298
|
-
|
|
299
|
-
Guidelines:
|
|
300
|
-
- Generate 6-8 questions that potential customers would ask
|
|
301
|
-
- Answers should be concise but informative (2-4 sentences)
|
|
302
|
-
- Questions should naturally include keywords from the brand identity
|
|
303
|
-
- Answers should demonstrate expertise and build trust
|
|
304
|
-
- Format for FAQPage schema compatibility
|
|
305
|
-
|
|
306
|
-
Output your response as valid JSON.`;
|
|
307
|
-
async function geoFaq(options) {
|
|
308
|
-
const cwd = process.cwd();
|
|
309
|
-
console.log(chalk.blue("\n\u2753 FAQ Schema Generator\n"));
|
|
310
|
-
const config = await loadGeoConfig(cwd);
|
|
311
|
-
if (!config.geo?.identityPhrase || !config.geo?.shortDescription) {
|
|
312
|
-
console.log(chalk.yellow("No identity defined."));
|
|
313
|
-
console.log(chalk.dim(`Run 'archon geo identity' first.
|
|
314
|
-
`));
|
|
315
|
-
return;
|
|
316
|
-
}
|
|
317
|
-
const { identityPhrase, shortDescription } = config.geo;
|
|
318
|
-
const { allowed, tier } = await checkStrongModelAccess();
|
|
319
|
-
if (!allowed) {
|
|
320
|
-
console.log(chalk.yellow(`[!] Your tier (${tier}) uses basic models.`));
|
|
321
|
-
console.log(chalk.dim("For better results, add credits or use BYOK mode.\n"));
|
|
322
|
-
}
|
|
323
|
-
console.log(chalk.dim("Generating FAQ content with AI...\n"));
|
|
324
|
-
const agent = new ArchitectAgent({ temperature: 0.7 });
|
|
325
|
-
const prompt = `Generate FAQ content for a product/service with:
|
|
326
|
-
- Brand phrase: "${identityPhrase}"
|
|
327
|
-
- Description: "${shortDescription}"
|
|
328
|
-
|
|
329
|
-
Generate 6-8 FAQs as JSON:
|
|
330
|
-
{
|
|
331
|
-
"faqs": [
|
|
332
|
-
{ "question": "What is...?", "answer": "..." },
|
|
333
|
-
...
|
|
334
|
-
]
|
|
335
|
-
}`;
|
|
336
|
-
const response = await agent.client.chat(
|
|
337
|
-
FAQ_SYSTEM_PROMPT,
|
|
338
|
-
prompt,
|
|
339
|
-
{ temperature: 0.7, maxTokens: 2e3 }
|
|
340
|
-
);
|
|
341
|
-
const jsonMatch = response.content.match(/\{[\s\S]*\}/);
|
|
342
|
-
if (!jsonMatch) {
|
|
343
|
-
console.log(chalk.red("Failed to generate FAQ content."));
|
|
344
|
-
return;
|
|
345
|
-
}
|
|
346
|
-
const parsed = JSON.parse(jsonMatch[0]);
|
|
347
|
-
const faqSchema = {
|
|
348
|
-
"@context": "https://schema.org",
|
|
349
|
-
"@type": "FAQPage",
|
|
350
|
-
mainEntity: parsed.faqs.map((faq) => ({
|
|
351
|
-
"@type": "Question",
|
|
352
|
-
name: faq.question,
|
|
353
|
-
acceptedAnswer: {
|
|
354
|
-
"@type": "Answer",
|
|
355
|
-
text: faq.answer
|
|
356
|
-
}
|
|
357
|
-
}))
|
|
358
|
-
};
|
|
359
|
-
const jsonLd = JSON.stringify(faqSchema, null, 2);
|
|
360
|
-
if (options.output) {
|
|
361
|
-
await writeFile(options.output, jsonLd, "utf-8");
|
|
362
|
-
console.log(chalk.green(`\u2705 FAQ schema written to ${options.output}`));
|
|
363
|
-
} else {
|
|
364
|
-
console.log(chalk.bold("Generated FAQPage JSON-LD:\n"));
|
|
365
|
-
console.log(chalk.cyan(jsonLd));
|
|
366
|
-
}
|
|
367
|
-
console.log();
|
|
368
|
-
}
|
|
369
|
-
async function geoAudit() {
|
|
370
|
-
const cwd = process.cwd();
|
|
371
|
-
console.log(chalk.blue("\n\u{1F50D} GEO Audit\n"));
|
|
372
|
-
const result = {
|
|
373
|
-
identityDefined: false,
|
|
374
|
-
phraseInH1: false,
|
|
375
|
-
phraseInMetaDescription: false,
|
|
376
|
-
hasOrganizationSchema: false,
|
|
377
|
-
hasServiceSchema: false,
|
|
378
|
-
hasFAQSchema: false,
|
|
379
|
-
issues: []
|
|
380
|
-
};
|
|
381
|
-
const config = await loadGeoConfig(cwd);
|
|
382
|
-
if (config.geo?.identityPhrase && config.geo?.shortDescription) {
|
|
383
|
-
result.identityDefined = true;
|
|
384
|
-
console.log(chalk.green("\u2705 Identity defined"));
|
|
385
|
-
console.log(chalk.dim(` Phrase: ${config.geo.identityPhrase}`));
|
|
386
|
-
} else {
|
|
387
|
-
result.issues.push('Identity not defined. Run "archon geo identity"');
|
|
388
|
-
console.log(chalk.red("\u274C Identity not defined"));
|
|
389
|
-
}
|
|
390
|
-
const htmlFiles = await glob("**/index.html", { cwd, ignore: ["**/node_modules/**", "**/dist/**"] });
|
|
391
|
-
const firstHtmlFile = htmlFiles[0];
|
|
392
|
-
if (firstHtmlFile && config.geo?.identityPhrase) {
|
|
393
|
-
const indexPath = join(cwd, firstHtmlFile);
|
|
394
|
-
const content = await readFile(indexPath, "utf-8");
|
|
395
|
-
const identityPhrase = config.geo.identityPhrase;
|
|
396
|
-
const firstKeyword = identityPhrase.toLowerCase().split(" ")[0] ?? "";
|
|
397
|
-
const h1Match = content.match(/<h1[^>]*>(.*?)<\/h1>/is);
|
|
398
|
-
if (h1Match?.[1] && h1Match[1].toLowerCase().includes(firstKeyword)) {
|
|
399
|
-
result.phraseInH1 = true;
|
|
400
|
-
console.log(chalk.green("\u2705 Brand keyword in H1"));
|
|
401
|
-
} else {
|
|
402
|
-
result.issues.push("Brand phrase keyword not found in H1");
|
|
403
|
-
console.log(chalk.yellow("[!] Brand keyword not in H1"));
|
|
404
|
-
}
|
|
405
|
-
const metaMatch = content.match(/<meta[^>]*name=["']description["'][^>]*content=["']([^"']*)["']/i);
|
|
406
|
-
if (metaMatch?.[1] && metaMatch[1].toLowerCase().includes(firstKeyword)) {
|
|
407
|
-
result.phraseInMetaDescription = true;
|
|
408
|
-
console.log(chalk.green("\u2705 Brand keyword in meta description"));
|
|
409
|
-
} else {
|
|
410
|
-
result.issues.push("Brand phrase keyword not found in meta description");
|
|
411
|
-
console.log(chalk.yellow("[!] Brand keyword not in meta description"));
|
|
412
|
-
}
|
|
413
|
-
if (content.includes("application/ld+json")) {
|
|
414
|
-
if (content.includes('"@type":"Organization"') || content.includes('"@type": "Organization"')) {
|
|
415
|
-
result.hasOrganizationSchema = true;
|
|
416
|
-
console.log(chalk.green("\u2705 Organization schema present"));
|
|
417
|
-
} else {
|
|
418
|
-
result.issues.push("Organization schema not found");
|
|
419
|
-
console.log(chalk.yellow("[!] Organization schema missing"));
|
|
420
|
-
}
|
|
421
|
-
if (content.includes('"@type":"Service"') || content.includes('"@type": "Service"')) {
|
|
422
|
-
result.hasServiceSchema = true;
|
|
423
|
-
console.log(chalk.green("\u2705 Service schema present"));
|
|
424
|
-
} else {
|
|
425
|
-
result.issues.push("Service schema not found");
|
|
426
|
-
console.log(chalk.yellow("[!] Service schema missing"));
|
|
427
|
-
}
|
|
428
|
-
if (content.includes('"@type":"FAQPage"') || content.includes('"@type": "FAQPage"')) {
|
|
429
|
-
result.hasFAQSchema = true;
|
|
430
|
-
console.log(chalk.green("\u2705 FAQPage schema present"));
|
|
431
|
-
} else {
|
|
432
|
-
result.issues.push("FAQPage schema not found");
|
|
433
|
-
console.log(chalk.yellow("[!] FAQPage schema missing"));
|
|
434
|
-
}
|
|
435
|
-
} else {
|
|
436
|
-
result.issues.push("No JSON-LD schemas found");
|
|
437
|
-
console.log(chalk.red("\u274C No JSON-LD schemas found"));
|
|
438
|
-
}
|
|
439
|
-
} else if (htmlFiles.length === 0) {
|
|
440
|
-
result.issues.push("No index.html found");
|
|
441
|
-
console.log(chalk.yellow("[!] No index.html found to audit"));
|
|
442
|
-
}
|
|
443
|
-
console.log();
|
|
444
|
-
const passed = result.issues.length === 0;
|
|
445
|
-
if (passed) {
|
|
446
|
-
console.log(chalk.green.bold("\u2705 GEO Audit Passed"));
|
|
447
|
-
} else {
|
|
448
|
-
console.log(chalk.yellow.bold(`[!] ${result.issues.length} issue(s) found`));
|
|
449
|
-
console.log();
|
|
450
|
-
console.log(chalk.bold("Recommendations:"));
|
|
451
|
-
result.issues.forEach((issue, i) => {
|
|
452
|
-
console.log(chalk.dim(` ${i + 1}. ${issue}`));
|
|
453
|
-
});
|
|
454
|
-
}
|
|
455
|
-
console.log();
|
|
456
|
-
await recordWebCheckResult(cwd, "geo", passed);
|
|
457
|
-
return result;
|
|
458
|
-
}
|
|
459
|
-
function createGeoCommand() {
|
|
460
|
-
const geo = new Command("geo").description("GEO (Generative Engine Optimization) for AI-powered SEO").addHelpText(
|
|
461
|
-
"after",
|
|
462
|
-
`
|
|
463
|
-
Examples:
|
|
464
|
-
archon geo identity Generate brand identity phrases
|
|
465
|
-
archon geo schema Generate JSON-LD Organization/Service schemas
|
|
466
|
-
archon geo schema --apply Insert JSON-LD into homepage
|
|
467
|
-
archon geo faq Generate FAQPage schema
|
|
468
|
-
archon geo audit Check GEO compliance status
|
|
469
|
-
`
|
|
470
|
-
);
|
|
471
|
-
geo.command("identity").description("Generate and save brand identity (7-word phrase + 50-word description)").action(async () => {
|
|
472
|
-
await geoIdentity();
|
|
473
|
-
});
|
|
474
|
-
geo.command("schema").description("Generate JSON-LD Organization and Service schemas").option("-o, --output <file>", "Write schema to file").option("-a, --apply", "Insert schema into homepage <head>").action(async (options) => {
|
|
475
|
-
await geoSchema(options);
|
|
476
|
-
});
|
|
477
|
-
geo.command("faq").description("Generate FAQPage JSON-LD schema").option("-o, --output <file>", "Write FAQ schema to file").action(async (options) => {
|
|
478
|
-
await geoFaq(options);
|
|
479
|
-
});
|
|
480
|
-
geo.command("audit").description("Audit GEO compliance (identity, schemas, placement)").action(async () => {
|
|
481
|
-
await geoAudit();
|
|
482
|
-
});
|
|
483
|
-
geo.action(async () => {
|
|
484
|
-
await geoAudit();
|
|
485
|
-
});
|
|
486
|
-
return geo;
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
export {
|
|
490
|
-
geoIdentity,
|
|
491
|
-
geoSchema,
|
|
492
|
-
geoFaq,
|
|
493
|
-
geoAudit,
|
|
494
|
-
createGeoCommand
|
|
495
|
-
};
|
package/dist/chunk-GGRW4NTA.js
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
// src/cli/config.ts
|
|
2
|
-
import { homedir } from "os";
|
|
3
|
-
import { join } from "path";
|
|
4
|
-
import { readFile, writeFile, mkdir, chmod, unlink } from "fs/promises";
|
|
5
|
-
import { existsSync } from "fs";
|
|
6
|
-
import { createClient } from "@supabase/supabase-js";
|
|
7
|
-
var CONFIG_DIR = join(homedir(), ".archon");
|
|
8
|
-
var CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
9
|
-
var SUPABASE_URL = "https://yjdkcepktrbabmzhcmrt.supabase.co";
|
|
10
|
-
var SUPABASE_ANON_KEY = "sb_publishable_XSGLVPfLZx-HA2uL6xsGCQ_KjAx2TIa";
|
|
11
|
-
function toIsoFromSupabaseExpiry(expiresAt) {
|
|
12
|
-
if (typeof expiresAt === "number" && Number.isFinite(expiresAt)) {
|
|
13
|
-
const millis = expiresAt > 1e12 ? expiresAt : expiresAt * 1e3;
|
|
14
|
-
return new Date(millis).toISOString();
|
|
15
|
-
}
|
|
16
|
-
return new Date(Date.now() + 36e5).toISOString();
|
|
17
|
-
}
|
|
18
|
-
function getAuthToken(config) {
|
|
19
|
-
return config.accessToken;
|
|
20
|
-
}
|
|
21
|
-
function getApiUrl(config) {
|
|
22
|
-
return config.apiUrl || "https://archondev-api.fly.dev";
|
|
23
|
-
}
|
|
24
|
-
async function ensureConfigDir() {
|
|
25
|
-
if (!existsSync(CONFIG_DIR)) {
|
|
26
|
-
await mkdir(CONFIG_DIR, { recursive: true, mode: 448 });
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
async function loadConfig() {
|
|
30
|
-
try {
|
|
31
|
-
if (!existsSync(CONFIG_FILE)) {
|
|
32
|
-
return {};
|
|
33
|
-
}
|
|
34
|
-
const content = await readFile(CONFIG_FILE, "utf-8");
|
|
35
|
-
return JSON.parse(content);
|
|
36
|
-
} catch {
|
|
37
|
-
return {};
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
async function saveConfig(config) {
|
|
41
|
-
await ensureConfigDir();
|
|
42
|
-
const content = JSON.stringify(config, null, 2);
|
|
43
|
-
await writeFile(CONFIG_FILE, content, { mode: 384 });
|
|
44
|
-
await chmod(CONFIG_FILE, 384);
|
|
45
|
-
}
|
|
46
|
-
async function clearConfig() {
|
|
47
|
-
if (existsSync(CONFIG_FILE)) {
|
|
48
|
-
await unlink(CONFIG_FILE);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
async function isAuthenticated() {
|
|
52
|
-
const config = await loadConfig();
|
|
53
|
-
if (!config.accessToken) {
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
if (!config.expiresAt) {
|
|
57
|
-
if (config.refreshToken) {
|
|
58
|
-
const refreshed = await refreshSession(config);
|
|
59
|
-
return refreshed;
|
|
60
|
-
}
|
|
61
|
-
return true;
|
|
62
|
-
}
|
|
63
|
-
const expiresAt = new Date(config.expiresAt);
|
|
64
|
-
const now = /* @__PURE__ */ new Date();
|
|
65
|
-
const fiveMinutesFromNow = new Date(now.getTime() + 5 * 60 * 1e3);
|
|
66
|
-
if (expiresAt < fiveMinutesFromNow) {
|
|
67
|
-
if (config.refreshToken) {
|
|
68
|
-
const refreshed = await refreshSession(config);
|
|
69
|
-
return refreshed;
|
|
70
|
-
}
|
|
71
|
-
if (expiresAt < now) {
|
|
72
|
-
return false;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return true;
|
|
76
|
-
}
|
|
77
|
-
async function refreshSession(config) {
|
|
78
|
-
if (!config.refreshToken) {
|
|
79
|
-
return false;
|
|
80
|
-
}
|
|
81
|
-
try {
|
|
82
|
-
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
|
|
83
|
-
auth: { flowType: "pkce" }
|
|
84
|
-
});
|
|
85
|
-
const { data, error } = await supabase.auth.refreshSession({
|
|
86
|
-
refresh_token: config.refreshToken
|
|
87
|
-
});
|
|
88
|
-
if (error || !data.session) {
|
|
89
|
-
return false;
|
|
90
|
-
}
|
|
91
|
-
await saveConfig({
|
|
92
|
-
...config,
|
|
93
|
-
accessToken: data.session.access_token,
|
|
94
|
-
refreshToken: data.session.refresh_token,
|
|
95
|
-
expiresAt: toIsoFromSupabaseExpiry(data.session.expires_at)
|
|
96
|
-
});
|
|
97
|
-
return true;
|
|
98
|
-
} catch {
|
|
99
|
-
return false;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
async function ensureValidSession() {
|
|
103
|
-
const isAuth = await isAuthenticated();
|
|
104
|
-
if (!isAuth) {
|
|
105
|
-
return null;
|
|
106
|
-
}
|
|
107
|
-
return await loadConfig();
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
export {
|
|
111
|
-
getAuthToken,
|
|
112
|
-
getApiUrl,
|
|
113
|
-
loadConfig,
|
|
114
|
-
saveConfig,
|
|
115
|
-
clearConfig,
|
|
116
|
-
isAuthenticated,
|
|
117
|
-
ensureValidSession
|
|
118
|
-
};
|
package/dist/chunk-M4LGRTLC.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
// src/cli/constants.ts
|
|
2
|
-
var SUPABASE_URL = "https://yjdkcepktrbabmzhcmrt.supabase.co";
|
|
3
|
-
var SUPABASE_ANON_KEY = "sb_publishable_XSGLVPfLZx-HA2uL6xsGCQ_KjAx2TIa";
|
|
4
|
-
var API_URL = "https://archondev-api.fly.dev";
|
|
5
|
-
|
|
6
|
-
export {
|
|
7
|
-
SUPABASE_URL,
|
|
8
|
-
SUPABASE_ANON_KEY,
|
|
9
|
-
API_URL
|
|
10
|
-
};
|
package/dist/client-PHW2C2HB.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createAnonSupabaseClient,
|
|
3
|
-
createAuthedSupabaseClient,
|
|
4
|
-
createPkceSupabaseClient
|
|
5
|
-
} from "./chunk-Q3GIFHIQ.js";
|
|
6
|
-
import "./chunk-4VNS5WPM.js";
|
|
7
|
-
export {
|
|
8
|
-
createAnonSupabaseClient,
|
|
9
|
-
createAuthedSupabaseClient,
|
|
10
|
-
createPkceSupabaseClient
|
|
11
|
-
};
|
package/dist/geo-BWH5PUBK.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createGeoCommand,
|
|
3
|
-
geoAudit,
|
|
4
|
-
geoFaq,
|
|
5
|
-
geoIdentity,
|
|
6
|
-
geoSchema
|
|
7
|
-
} from "./chunk-CFJECC3B.js";
|
|
8
|
-
import "./chunk-3ASILTFB.js";
|
|
9
|
-
import "./chunk-D3TVDCJA.js";
|
|
10
|
-
import "./chunk-NIIFUBOE.js";
|
|
11
|
-
import "./chunk-7C6JELBL.js";
|
|
12
|
-
import "./chunk-GGRW4NTA.js";
|
|
13
|
-
import "./chunk-4VNS5WPM.js";
|
|
14
|
-
export {
|
|
15
|
-
createGeoCommand,
|
|
16
|
-
geoAudit,
|
|
17
|
-
geoFaq,
|
|
18
|
-
geoIdentity,
|
|
19
|
-
geoSchema
|
|
20
|
-
};
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
handleTierSetup,
|
|
3
|
-
promptTierSelection,
|
|
4
|
-
runGuidedAIConfig,
|
|
5
|
-
showTierSwitchMenu,
|
|
6
|
-
showUpgradeMenu,
|
|
7
|
-
updateUserTier
|
|
8
|
-
} from "./chunk-ONH6Y3CS.js";
|
|
9
|
-
import "./chunk-GGRW4NTA.js";
|
|
10
|
-
import "./chunk-4VNS5WPM.js";
|
|
11
|
-
export {
|
|
12
|
-
handleTierSetup,
|
|
13
|
-
promptTierSelection,
|
|
14
|
-
runGuidedAIConfig,
|
|
15
|
-
showTierSwitchMenu,
|
|
16
|
-
showUpgradeMenu,
|
|
17
|
-
updateUserTier
|
|
18
|
-
};
|