@akropolys/cli 1.5.9 → 1.6.1
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 +45 -0
- package/dist/index.js +34 -17
- package/package.json +10 -6
- package/src/commands/doctor.ts +0 -87
- package/src/commands/init.ts +0 -49
- package/src/commands/inspect.ts +0 -100
- package/src/index.ts +0 -38
- package/tsconfig.json +0 -13
- package/tsup.config.ts +0 -11
package/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# @akropolys/cli
|
|
2
|
+
|
|
3
|
+
Command-line utilities for [Akropolys](https://akropolys.cloud): scaffold local config, check connectivity, and lint catalog payloads before you ingest them.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @akropolys/cli
|
|
9
|
+
# or run on demand
|
|
10
|
+
npx @akropolys/cli <command>
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Commands
|
|
14
|
+
|
|
15
|
+
### `akropolys init`
|
|
16
|
+
|
|
17
|
+
Interactively writes an `.env` with your site credentials:
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
NEXT_PUBLIC_AKROPOLYS_SITE_ID=...
|
|
21
|
+
NEXT_PUBLIC_AKROPOLYS_API_TOKEN=...
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### `akropolys doctor`
|
|
25
|
+
|
|
26
|
+
Verifies your local config and that the API is reachable. Reads `NEXT_PUBLIC_AKROPOLYS_*` or `VITE_AKROPOLYS_*` from `.env` / `.env.local`.
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
akropolys doctor # health check
|
|
30
|
+
akropolys doctor -v # also print the resolved config
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### `akropolys inspect [file]`
|
|
34
|
+
|
|
35
|
+
Statically checks a catalog JSON payload for ingestion issues — missing stable identifier, sparse attributes — before you push it.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
akropolys inspect catalog.json
|
|
39
|
+
cat catalog.json | akropolys inspect --stdin
|
|
40
|
+
akropolys inspect catalog.json --strict # exit 3 if any warning fires
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## License
|
|
44
|
+
|
|
45
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -43,20 +43,8 @@ async function runInit() {
|
|
|
43
43
|
try {
|
|
44
44
|
const siteId = await question(rl, import_picocolors.default.cyan("? Enter your Akropolys Site ID: "));
|
|
45
45
|
const apiToken = await question(rl, import_picocolors.default.cyan("? Enter your Akropolys API Token: "));
|
|
46
|
-
const apiUrlInput = await question(rl, import_picocolors.default.cyan("? Enter your Akropolys API URL (default: https://api.akropolys.io): "));
|
|
47
|
-
const apiUrl = apiUrlInput.trim() || "https://api.akropolys.io";
|
|
48
|
-
console.log(import_picocolors.default.cyan("? Select your vertical:"));
|
|
49
|
-
console.log(" 1. commerce");
|
|
50
|
-
console.log(" 2. property");
|
|
51
|
-
console.log(" 3. motor");
|
|
52
|
-
const verticalIndex = await question(rl, import_picocolors.default.cyan(" Select (1-3, default: 1): "));
|
|
53
|
-
let vertical = "commerce";
|
|
54
|
-
if (verticalIndex === "2") vertical = "property";
|
|
55
|
-
else if (verticalIndex === "3") vertical = "motor";
|
|
56
46
|
const envContent = `NEXT_PUBLIC_AKROPOLYS_SITE_ID=${siteId.trim()}
|
|
57
47
|
NEXT_PUBLIC_AKROPOLYS_API_TOKEN=${apiToken.trim()}
|
|
58
|
-
NEXT_PUBLIC_AKROPOLYS_API_URL=${apiUrl.trim()}
|
|
59
|
-
NEXT_PUBLIC_AKROPOLYS_VERTICAL=${vertical}
|
|
60
48
|
`;
|
|
61
49
|
import_fs.default.writeFileSync(".env", envContent, "utf-8");
|
|
62
50
|
console.log(import_picocolors.default.dim("\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
@@ -101,13 +89,11 @@ async function runDoctor(options) {
|
|
|
101
89
|
loadEnv();
|
|
102
90
|
const siteId = process.env.NEXT_PUBLIC_AKROPOLYS_SITE_ID || process.env.VITE_AKROPOLYS_SITE_ID || "";
|
|
103
91
|
const apiToken = process.env.NEXT_PUBLIC_AKROPOLYS_API_TOKEN || process.env.VITE_AKROPOLYS_API_TOKEN || "";
|
|
104
|
-
const apiUrl = process.env.NEXT_PUBLIC_AKROPOLYS_API_URL || process.env.VITE_AKROPOLYS_API_URL || "https://api.akropolys.
|
|
105
|
-
const vertical = process.env.NEXT_PUBLIC_AKROPOLYS_VERTICAL || process.env.VITE_AKROPOLYS_VERTICAL || "commerce";
|
|
92
|
+
const apiUrl = process.env.NEXT_PUBLIC_AKROPOLYS_API_URL || process.env.VITE_AKROPOLYS_API_URL || "https://api.akropolys.cloud/v1";
|
|
106
93
|
if (options.verbose) {
|
|
107
94
|
console.log(import_picocolors2.default.dim(`[Verbose] Site ID: ${siteId || "<not set>"}`));
|
|
108
95
|
console.log(import_picocolors2.default.dim(`[Verbose] API Token: ${apiToken ? "********" : "<not set>"}`));
|
|
109
96
|
console.log(import_picocolors2.default.dim(`[Verbose] API URL: ${apiUrl}`));
|
|
110
|
-
console.log(import_picocolors2.default.dim(`[Verbose] Vertical: ${vertical}`));
|
|
111
97
|
}
|
|
112
98
|
if (!siteId) {
|
|
113
99
|
console.log(import_picocolors2.default.red("\u274C Configuration: Site ID is missing. Set NEXT_PUBLIC_AKROPOLYS_SITE_ID in your env."));
|
|
@@ -136,7 +122,6 @@ async function runDoctor(options) {
|
|
|
136
122
|
process.exit(2);
|
|
137
123
|
}
|
|
138
124
|
console.log(import_picocolors2.default.green(`\u2713 Connection: Successfully connected to ${apiUrl} (ping: ${duration}ms)`));
|
|
139
|
-
console.log(import_picocolors2.default.green(`\u2713 Integration: Site vertical configured as "${vertical}"`));
|
|
140
125
|
console.log(import_picocolors2.default.bold(import_picocolors2.default.green("\nStatus: Healthy (All configuration and connectivity checks passed)")));
|
|
141
126
|
process.exit(0);
|
|
142
127
|
} catch (err) {
|
|
@@ -224,9 +209,41 @@ async function runInspect(filePath, options) {
|
|
|
224
209
|
process.exit(0);
|
|
225
210
|
}
|
|
226
211
|
|
|
212
|
+
// package.json
|
|
213
|
+
var package_default = {
|
|
214
|
+
name: "@akropolys/cli",
|
|
215
|
+
version: "1.6.1",
|
|
216
|
+
description: "Akropolys CLI \u2014 diagnostic, workspace setup, and payload inspection utility.",
|
|
217
|
+
license: "MIT",
|
|
218
|
+
publishConfig: {
|
|
219
|
+
access: "public"
|
|
220
|
+
},
|
|
221
|
+
main: "dist/index.js",
|
|
222
|
+
bin: {
|
|
223
|
+
akropolys: "dist/index.js"
|
|
224
|
+
},
|
|
225
|
+
files: [
|
|
226
|
+
"dist",
|
|
227
|
+
"README.md"
|
|
228
|
+
],
|
|
229
|
+
scripts: {
|
|
230
|
+
build: "tsup",
|
|
231
|
+
dev: "tsup --watch"
|
|
232
|
+
},
|
|
233
|
+
dependencies: {
|
|
234
|
+
commander: "^12.0.0",
|
|
235
|
+
picocolors: "^1.0.0"
|
|
236
|
+
},
|
|
237
|
+
devDependencies: {
|
|
238
|
+
tsup: "^8.0.0",
|
|
239
|
+
typescript: "^5.0.0",
|
|
240
|
+
"@types/node": "^20.0.0"
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
|
|
227
244
|
// src/index.ts
|
|
228
245
|
var program = new import_commander.Command();
|
|
229
|
-
program.name("akropolys").description("Akropolys Command Line Tool \u2014 Developer diagnostics, setup helper, and structural inspector.").version(
|
|
246
|
+
program.name("akropolys").description("Akropolys Command Line Tool \u2014 Developer diagnostics, setup helper, and structural inspector.").version(package_default.version);
|
|
230
247
|
program.command("init").description("Configure the local workspace by generating a default .env file template.").action(async () => {
|
|
231
248
|
await runInit();
|
|
232
249
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akropolys/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.1",
|
|
4
4
|
"description": "Akropolys CLI — diagnostic, workspace setup, and payload inspection utility.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
"bin": {
|
|
11
11
|
"akropolys": "dist/index.js"
|
|
12
12
|
},
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"commander": "^12.0.0",
|
|
19
19
|
"picocolors": "^1.0.0"
|
|
@@ -22,5 +22,9 @@
|
|
|
22
22
|
"tsup": "^8.0.0",
|
|
23
23
|
"typescript": "^5.0.0",
|
|
24
24
|
"@types/node": "^20.0.0"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsup",
|
|
28
|
+
"dev": "tsup --watch"
|
|
25
29
|
}
|
|
26
|
-
}
|
|
30
|
+
}
|
package/src/commands/doctor.ts
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import pc from 'picocolors';
|
|
3
|
-
|
|
4
|
-
export function loadEnv() {
|
|
5
|
-
const envPaths = ['.env', '.env.local'];
|
|
6
|
-
for (const envPath of envPaths) {
|
|
7
|
-
if (fs.existsSync(envPath)) {
|
|
8
|
-
const content = fs.readFileSync(envPath, 'utf-8');
|
|
9
|
-
const lines = content.split(/\r?\n/);
|
|
10
|
-
for (const line of lines) {
|
|
11
|
-
const trimmed = line.trim();
|
|
12
|
-
if (!trimmed || trimmed.startsWith('#')) continue;
|
|
13
|
-
const eqIdx = trimmed.indexOf('=');
|
|
14
|
-
if (eqIdx > 0) {
|
|
15
|
-
const key = trimmed.substring(0, eqIdx).trim();
|
|
16
|
-
const value = trimmed.substring(eqIdx + 1).trim().replace(/^['"]|['"]$/g, '');
|
|
17
|
-
if (key) {
|
|
18
|
-
process.env[key] = value;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export async function runDoctor(options: { verbose?: boolean }) {
|
|
27
|
-
console.log(pc.bold('\nAkropolys Doctor'));
|
|
28
|
-
console.log(pc.dim('─────────────────────────'));
|
|
29
|
-
|
|
30
|
-
loadEnv();
|
|
31
|
-
|
|
32
|
-
const siteId = process.env.NEXT_PUBLIC_AKROPOLYS_SITE_ID || process.env.VITE_AKROPOLYS_SITE_ID || '';
|
|
33
|
-
const apiToken = process.env.NEXT_PUBLIC_AKROPOLYS_API_TOKEN || process.env.VITE_AKROPOLYS_API_TOKEN || '';
|
|
34
|
-
const apiUrl = process.env.NEXT_PUBLIC_AKROPOLYS_API_URL || process.env.VITE_AKROPOLYS_API_URL || 'https://api.akropolys.io';
|
|
35
|
-
const vertical = process.env.NEXT_PUBLIC_AKROPOLYS_VERTICAL || process.env.VITE_AKROPOLYS_VERTICAL || 'commerce';
|
|
36
|
-
|
|
37
|
-
if (options.verbose) {
|
|
38
|
-
console.log(pc.dim(`[Verbose] Site ID: ${siteId || '<not set>'}`));
|
|
39
|
-
console.log(pc.dim(`[Verbose] API Token: ${apiToken ? '********' : '<not set>'}`));
|
|
40
|
-
console.log(pc.dim(`[Verbose] API URL: ${apiUrl}`));
|
|
41
|
-
console.log(pc.dim(`[Verbose] Vertical: ${vertical}`));
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// 1. Configuration check
|
|
45
|
-
if (!siteId) {
|
|
46
|
-
console.log(pc.red('❌ Configuration: Site ID is missing. Set NEXT_PUBLIC_AKROPOLYS_SITE_ID in your env.'));
|
|
47
|
-
process.exit(1);
|
|
48
|
-
}
|
|
49
|
-
console.log(pc.green(`✓ Configuration: Site ID detected (${siteId})`));
|
|
50
|
-
|
|
51
|
-
if (!apiToken) {
|
|
52
|
-
console.log(pc.red('❌ Environment: API Token is missing. Set NEXT_PUBLIC_AKROPOLYS_API_TOKEN in your env.'));
|
|
53
|
-
process.exit(1);
|
|
54
|
-
}
|
|
55
|
-
console.log(pc.green('✓ Environment: API Token detected'));
|
|
56
|
-
|
|
57
|
-
// 2. Connectivity check
|
|
58
|
-
const start = Date.now();
|
|
59
|
-
try {
|
|
60
|
-
const res = await fetch(`${apiUrl}/health`, {
|
|
61
|
-
method: 'GET',
|
|
62
|
-
headers: {
|
|
63
|
-
'X-Akropolys-Token': apiToken,
|
|
64
|
-
'X-Akropolys-Site': siteId,
|
|
65
|
-
},
|
|
66
|
-
}).catch(err => {
|
|
67
|
-
// Throw fetch failures
|
|
68
|
-
throw new Error(`Fetch failed: ${err.message}`);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
const duration = Date.now() - start;
|
|
72
|
-
|
|
73
|
-
if (!res.ok) {
|
|
74
|
-
console.log(pc.red(`❌ Connection: API responded with status ${res.status} (Ping: ${duration}ms)`));
|
|
75
|
-
process.exit(2);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
console.log(pc.green(`✓ Connection: Successfully connected to ${apiUrl} (ping: ${duration}ms)`));
|
|
79
|
-
console.log(pc.green(`✓ Integration: Site vertical configured as "${vertical}"`));
|
|
80
|
-
|
|
81
|
-
console.log(pc.bold(pc.green('\nStatus: Healthy (All configuration and connectivity checks passed)')));
|
|
82
|
-
process.exit(0);
|
|
83
|
-
} catch (err: any) {
|
|
84
|
-
console.log(pc.red(`❌ Connection: Unreachable API at ${apiUrl}. Error: ${err.message}`));
|
|
85
|
-
process.exit(2);
|
|
86
|
-
}
|
|
87
|
-
}
|
package/src/commands/init.ts
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import readline from 'readline';
|
|
2
|
-
import fs from 'fs';
|
|
3
|
-
import pc from 'picocolors';
|
|
4
|
-
|
|
5
|
-
const question = (rl: readline.Interface, query: string): Promise<string> => {
|
|
6
|
-
return new Promise((resolve) => rl.question(query, resolve));
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export async function runInit() {
|
|
10
|
-
console.log(pc.bold(pc.cyan('\nConfiguring Akropolys Workspace...')));
|
|
11
|
-
console.log(pc.dim('─────────────────────────'));
|
|
12
|
-
|
|
13
|
-
const rl = readline.createInterface({
|
|
14
|
-
input: process.stdin,
|
|
15
|
-
output: process.stdout,
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
try {
|
|
19
|
-
const siteId = await question(rl, pc.cyan('? Enter your Akropolys Site ID: '));
|
|
20
|
-
const apiToken = await question(rl, pc.cyan('? Enter your Akropolys API Token: '));
|
|
21
|
-
const apiUrlInput = await question(rl, pc.cyan('? Enter your Akropolys API URL (default: https://api.akropolys.io): '));
|
|
22
|
-
const apiUrl = apiUrlInput.trim() || 'https://api.akropolys.io';
|
|
23
|
-
|
|
24
|
-
console.log(pc.cyan('? Select your vertical:'));
|
|
25
|
-
console.log(' 1. commerce');
|
|
26
|
-
console.log(' 2. property');
|
|
27
|
-
console.log(' 3. motor');
|
|
28
|
-
const verticalIndex = await question(rl, pc.cyan(' Select (1-3, default: 1): '));
|
|
29
|
-
let vertical = 'commerce';
|
|
30
|
-
if (verticalIndex === '2') vertical = 'property';
|
|
31
|
-
else if (verticalIndex === '3') vertical = 'motor';
|
|
32
|
-
|
|
33
|
-
const envContent = `NEXT_PUBLIC_AKROPOLYS_SITE_ID=${siteId.trim()}
|
|
34
|
-
NEXT_PUBLIC_AKROPOLYS_API_TOKEN=${apiToken.trim()}
|
|
35
|
-
NEXT_PUBLIC_AKROPOLYS_API_URL=${apiUrl.trim()}
|
|
36
|
-
NEXT_PUBLIC_AKROPOLYS_VERTICAL=${vertical}
|
|
37
|
-
`;
|
|
38
|
-
|
|
39
|
-
fs.writeFileSync('.env', envContent, 'utf-8');
|
|
40
|
-
console.log(pc.dim('\n─────────────────────────'));
|
|
41
|
-
console.log(pc.green('✓ Generated .env with configuration parameters.'));
|
|
42
|
-
console.log(pc.green('✓ Saved config template.'));
|
|
43
|
-
} catch (err: any) {
|
|
44
|
-
console.error(pc.red(`\n❌ Error generating configuration: ${err.message}`));
|
|
45
|
-
process.exit(1);
|
|
46
|
-
} finally {
|
|
47
|
-
rl.close();
|
|
48
|
-
}
|
|
49
|
-
}
|
package/src/commands/inspect.ts
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import pc from 'picocolors';
|
|
3
|
-
|
|
4
|
-
function readStdin(): Promise<string> {
|
|
5
|
-
return new Promise((resolve, reject) => {
|
|
6
|
-
let data = '';
|
|
7
|
-
process.stdin.setEncoding('utf-8');
|
|
8
|
-
process.stdin.on('readable', () => {
|
|
9
|
-
let chunk;
|
|
10
|
-
while ((chunk = process.stdin.read()) !== null) {
|
|
11
|
-
data += chunk;
|
|
12
|
-
}
|
|
13
|
-
});
|
|
14
|
-
process.stdin.on('end', () => {
|
|
15
|
-
resolve(data);
|
|
16
|
-
});
|
|
17
|
-
process.stdin.on('error', (err) => {
|
|
18
|
-
reject(err);
|
|
19
|
-
});
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export async function runInspect(
|
|
24
|
-
filePath: string | undefined,
|
|
25
|
-
options: { stdin?: boolean; strict?: boolean }
|
|
26
|
-
) {
|
|
27
|
-
console.log(pc.bold('\nAkropolys Inspect'));
|
|
28
|
-
console.log(pc.dim('─────────────────────────'));
|
|
29
|
-
|
|
30
|
-
let rawData = '';
|
|
31
|
-
|
|
32
|
-
// 1. Read input
|
|
33
|
-
try {
|
|
34
|
-
if (options.stdin || (!filePath && !process.stdin.isTTY)) {
|
|
35
|
-
rawData = await readStdin();
|
|
36
|
-
} else if (filePath) {
|
|
37
|
-
if (!fs.existsSync(filePath)) {
|
|
38
|
-
console.error(pc.red(`❌ Error: File not found at "${filePath}"`));
|
|
39
|
-
process.exit(1);
|
|
40
|
-
}
|
|
41
|
-
rawData = fs.readFileSync(filePath, 'utf-8');
|
|
42
|
-
} else {
|
|
43
|
-
console.error(pc.red('❌ Error: Provide a file path or pipe via standard input using --stdin'));
|
|
44
|
-
process.exit(1);
|
|
45
|
-
}
|
|
46
|
-
} catch (err: any) {
|
|
47
|
-
console.error(pc.red(`❌ Error reading input: ${err.message}`));
|
|
48
|
-
process.exit(1);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// 2. Parse JSON
|
|
52
|
-
let items: any[] = [];
|
|
53
|
-
try {
|
|
54
|
-
const parsed = JSON.parse(rawData.trim());
|
|
55
|
-
items = Array.isArray(parsed) ? parsed : [parsed];
|
|
56
|
-
} catch (err: any) {
|
|
57
|
-
console.error(pc.red(`❌ Error parsing JSON: Invalid JSON structure. ${err.message}`));
|
|
58
|
-
process.exit(1);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
console.log(pc.cyan(`Parsed ${items.length} catalog items.`));
|
|
62
|
-
console.log(pc.dim('\nIngestion Quality Diagnostics:'));
|
|
63
|
-
|
|
64
|
-
let warningsCount = 0;
|
|
65
|
-
|
|
66
|
-
// 3. Scan items against Registry Rules
|
|
67
|
-
items.forEach((item, index) => {
|
|
68
|
-
const identifier = item.id || item.productId || item.slug || item.url || item.name || `item at index ${index}`;
|
|
69
|
-
|
|
70
|
-
// AP001: Missing Stable Identifier
|
|
71
|
-
const hasId = item.id !== undefined && item.id !== null && item.id !== '';
|
|
72
|
-
const hasProductId = item.productId !== undefined && item.productId !== null && item.productId !== '';
|
|
73
|
-
const hasSlug = item.slug !== undefined && item.slug !== null && item.slug !== '';
|
|
74
|
-
const hasUrl = item.url !== undefined && item.url !== null && item.url !== '';
|
|
75
|
-
const hasName = item.name !== undefined && item.name !== null && item.name !== '';
|
|
76
|
-
|
|
77
|
-
if (!hasId && !hasProductId && !hasSlug && !hasUrl && !hasName) {
|
|
78
|
-
console.log(` ${pc.yellow('⚠')} [AP001] Missing Stable Identifier: "${identifier}" ➔ Deduplication & correlation unavailable`);
|
|
79
|
-
warningsCount++;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// AP002: Low-Signal Payload (sparse payload: fewer than 2 keys, or only identifier is defined)
|
|
83
|
-
const keysCount = Object.keys(item).length;
|
|
84
|
-
if (keysCount < 2) {
|
|
85
|
-
console.log(` ${pc.yellow('⚠')} [AP002] Low-Signal Payload: "${identifier}" has sparse attributes ➔ Search vector quality reduced`);
|
|
86
|
-
warningsCount++;
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
console.log(pc.dim('\n─────────────────────────'));
|
|
91
|
-
console.log(pc.bold(`Inspect complete: ${items.length} items checked, ${warningsCount} warnings flagged.`));
|
|
92
|
-
|
|
93
|
-
// 4. Exit codes: strict vs non-strict
|
|
94
|
-
if (warningsCount > 0 && options.strict) {
|
|
95
|
-
console.log(pc.red('Exit code 3: strict mode failed due to warnings.'));
|
|
96
|
-
process.exit(3);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
process.exit(0);
|
|
100
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import { runInit } from './commands/init';
|
|
3
|
-
import { runDoctor } from './commands/doctor';
|
|
4
|
-
import { runInspect } from './commands/inspect';
|
|
5
|
-
|
|
6
|
-
const program = new Command();
|
|
7
|
-
|
|
8
|
-
program
|
|
9
|
-
.name('akropolys')
|
|
10
|
-
.description('Akropolys Command Line Tool — Developer diagnostics, setup helper, and structural inspector.')
|
|
11
|
-
.version('1.0.0');
|
|
12
|
-
|
|
13
|
-
program
|
|
14
|
-
.command('init')
|
|
15
|
-
.description('Configure the local workspace by generating a default .env file template.')
|
|
16
|
-
.action(async () => {
|
|
17
|
-
await runInit();
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
program
|
|
21
|
-
.command('doctor')
|
|
22
|
-
.description('Perform a health check consolidating local configuration values and backend API reachability.')
|
|
23
|
-
.option('-v, --verbose', 'Include verbose logs and configuration dumps.')
|
|
24
|
-
.action(async (options) => {
|
|
25
|
-
await runDoctor(options);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
program
|
|
29
|
-
.command('inspect')
|
|
30
|
-
.description('Statically inspect a catalog payload file or stream against the Akropolys Anti-Pattern Registry.')
|
|
31
|
-
.argument('[file]', 'Path to the local catalog JSON file.')
|
|
32
|
-
.option('--stdin', 'Force reading data from standard input.')
|
|
33
|
-
.option('--strict', 'Fail the process (exit code 3) if any structural registry warnings are triggered.')
|
|
34
|
-
.action(async (file, options) => {
|
|
35
|
-
await runInspect(file, options);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
program.parse(process.argv);
|
package/tsconfig.json
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "NodeNext",
|
|
5
|
-
"moduleResolution": "NodeNext",
|
|
6
|
-
"esModuleInterop": true,
|
|
7
|
-
"forceConsistentCasingInFileNames": true,
|
|
8
|
-
"strict": true,
|
|
9
|
-
"skipLibCheck": true,
|
|
10
|
-
"outDir": "./dist"
|
|
11
|
-
},
|
|
12
|
-
"include": ["src/**/*"]
|
|
13
|
-
}
|