@mytegroupinc/myte-core 0.0.46 → 0.0.49
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 +104 -43
- package/cli.js +1896 -430
- package/lib/certification-manifest.js +178 -0
- package/package.json +7 -4
- package/scripts/feedback-certification-cleanup.js +53 -0
- package/scripts/feedback-live-full-harness.js +929 -122
- package/scripts/project-assistant-read-certification.js +258 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const fs = require("node:fs");
|
|
5
|
+
const os = require("node:os");
|
|
6
|
+
const path = require("node:path");
|
|
7
|
+
const { spawnSync } = require("node:child_process");
|
|
8
|
+
const { randomUUID } = require("node:crypto");
|
|
9
|
+
|
|
10
|
+
const CLI_PATH = path.resolve(__dirname, "..", "cli.js");
|
|
11
|
+
|
|
12
|
+
const ROUTE_MATRIX = [
|
|
13
|
+
{ id: "doctor", kind: "transport", mutation: "none" },
|
|
14
|
+
{ id: "config", kind: "read", mutation: "none" },
|
|
15
|
+
{ id: "bootstrap", kind: "read/local-sync", mutation: "local_temp_only" },
|
|
16
|
+
{ id: "feedback-sync", kind: "read/local-sync", mutation: "local_temp_only" },
|
|
17
|
+
{ id: "sync-qaqc", kind: "read/local-sync", mutation: "local_temp_only" },
|
|
18
|
+
{ id: "suggestions-sync", kind: "read/local-sync", mutation: "local_temp_only" },
|
|
19
|
+
{ id: "feedback-get", kind: "read", mutation: "none", conditional: "feedback_id" },
|
|
20
|
+
{ id: "feedback-history", kind: "read", mutation: "none", conditional: "feedback_id" },
|
|
21
|
+
{ id: "feedback-prd-versions", kind: "read", mutation: "none", conditional: "feedback_id" },
|
|
22
|
+
{ id: "feedback-prd-diff", kind: "read", mutation: "none", conditional: "version_id" },
|
|
23
|
+
{ id: "query", kind: "inference-job", mutation: "ephemeral_job", conditional: "--include-query" },
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
function parseArgs(argv) {
|
|
27
|
+
const args = {};
|
|
28
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
29
|
+
const token = argv[index];
|
|
30
|
+
if (!token.startsWith("--")) continue;
|
|
31
|
+
const key = token.slice(2);
|
|
32
|
+
const next = argv[index + 1];
|
|
33
|
+
if (!next || next.startsWith("--")) {
|
|
34
|
+
args[key] = true;
|
|
35
|
+
} else {
|
|
36
|
+
args[key] = next;
|
|
37
|
+
index += 1;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return args;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function parseJsonOutput(result, command) {
|
|
44
|
+
const text = String(result.stdout || "").trim();
|
|
45
|
+
if (!text) return null;
|
|
46
|
+
try {
|
|
47
|
+
return JSON.parse(text);
|
|
48
|
+
} catch {
|
|
49
|
+
throw new Error(`${command} did not return JSON.`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function safeCommandLabel(args) {
|
|
54
|
+
if (args[0] === "feedback") {
|
|
55
|
+
return `myte feedback ${String(args[1] || "").trim() || "<subcommand>"}`;
|
|
56
|
+
}
|
|
57
|
+
if (args[0] === "suggestions") {
|
|
58
|
+
return `myte suggestions ${String(args[1] || "").trim() || "<subcommand>"}`;
|
|
59
|
+
}
|
|
60
|
+
if (args[0] === "query") {
|
|
61
|
+
return "myte query <redacted>";
|
|
62
|
+
}
|
|
63
|
+
return `myte ${String(args[0] || "").trim() || "<command>"}`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function runCli(args, { cwd, timeoutMs = 360000 } = {}) {
|
|
67
|
+
const started = Date.now();
|
|
68
|
+
const result = spawnSync(process.execPath, [CLI_PATH, ...args], {
|
|
69
|
+
cwd,
|
|
70
|
+
env: process.env,
|
|
71
|
+
encoding: "utf8",
|
|
72
|
+
timeout: timeoutMs,
|
|
73
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
74
|
+
});
|
|
75
|
+
const command = safeCommandLabel(args);
|
|
76
|
+
const parsed = parseJsonOutput(result, command);
|
|
77
|
+
return {
|
|
78
|
+
id: command.replace(/^myte\s+/, "").replace(/\s+/g, "-"),
|
|
79
|
+
command,
|
|
80
|
+
ok: result.status === 0,
|
|
81
|
+
exit_code: result.status,
|
|
82
|
+
duration_ms: Date.now() - started,
|
|
83
|
+
data: parsed,
|
|
84
|
+
error: result.status === 0
|
|
85
|
+
? null
|
|
86
|
+
: String(result.stderr || parsed?.message || "Command failed.").trim().slice(0, 2000),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function firstFeedbackId(feedbackPath) {
|
|
91
|
+
if (!fs.existsSync(feedbackPath)) return null;
|
|
92
|
+
const text = fs.readFileSync(feedbackPath, "utf8");
|
|
93
|
+
const match = text.match(/^\s*(?:-\s+)?feedback_id:\s*["']?([^"'\s]+)["']?\s*$/m);
|
|
94
|
+
return match ? match[1] : null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function versionIdentifier(version) {
|
|
98
|
+
return String(version?.version_id || version?._id || "").trim() || null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function versionDocumentIdentifier(version) {
|
|
102
|
+
const documentSet =
|
|
103
|
+
version?.prd_document_set && typeof version.prd_document_set === "object"
|
|
104
|
+
? version.prd_document_set
|
|
105
|
+
: null;
|
|
106
|
+
const documents = Array.isArray(version?.prd_documents)
|
|
107
|
+
? version.prd_documents
|
|
108
|
+
: Array.isArray(documentSet?.documents)
|
|
109
|
+
? documentSet.documents
|
|
110
|
+
: [];
|
|
111
|
+
return String(
|
|
112
|
+
version?.primary_document_id
|
|
113
|
+
|| documentSet?.primary_document_id
|
|
114
|
+
|| documents[0]?.document_id
|
|
115
|
+
|| "",
|
|
116
|
+
).trim() || null;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function baseArgs(args) {
|
|
120
|
+
const result = [];
|
|
121
|
+
if (args["base-url"]) result.push("--base-url", String(args["base-url"]));
|
|
122
|
+
result.push("--timeout-ms", String(args["timeout-ms"] || 300000));
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function main() {
|
|
127
|
+
const args = parseArgs(process.argv.slice(2));
|
|
128
|
+
if (!args["confirm-read"]) {
|
|
129
|
+
console.log(JSON.stringify({
|
|
130
|
+
ok: true,
|
|
131
|
+
dry_run: true,
|
|
132
|
+
message: "No network or project mutation was performed.",
|
|
133
|
+
route_matrix: ROUTE_MATRIX,
|
|
134
|
+
mutation_harnesses: [
|
|
135
|
+
"feedback-live-full-harness.js",
|
|
136
|
+
"mission-live-full-harness.js",
|
|
137
|
+
"mission-live-disposable-harness.js",
|
|
138
|
+
],
|
|
139
|
+
}, null, 2));
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (!process.env.MYTE_API_KEY && !process.env.MYTE_PROJECT_API_KEY) {
|
|
143
|
+
throw new Error("Missing MYTE_API_KEY or MYTE_PROJECT_API_KEY.");
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const runId = String(args["run-id"] || randomUUID());
|
|
147
|
+
const workspace = path.resolve(
|
|
148
|
+
args.workspace || fs.mkdtempSync(path.join(os.tmpdir(), `myte-read-cert-${runId}-`)),
|
|
149
|
+
);
|
|
150
|
+
const outputDir = path.join(workspace, "MyteCommandCenter");
|
|
151
|
+
fs.mkdirSync(workspace, { recursive: true });
|
|
152
|
+
const shared = baseArgs(args);
|
|
153
|
+
const checks = [];
|
|
154
|
+
|
|
155
|
+
const doctor = runCli(["doctor", "--json", ...shared], { cwd: workspace, timeoutMs: 60000 });
|
|
156
|
+
checks.push({ ...doctor, data: doctor.data ? {
|
|
157
|
+
ok: doctor.data.ok,
|
|
158
|
+
failure_layer: doctor.data.failure_layer,
|
|
159
|
+
runtime: doctor.data.runtime,
|
|
160
|
+
api: doctor.data.api,
|
|
161
|
+
project_key: doctor.data.project_key,
|
|
162
|
+
proxy: doctor.data.proxy,
|
|
163
|
+
dns: doctor.data.dns,
|
|
164
|
+
direct_transport: doctor.data.direct_transport,
|
|
165
|
+
config_probe: doctor.data.config_probe,
|
|
166
|
+
} : null });
|
|
167
|
+
if (!doctor.ok) {
|
|
168
|
+
console.log(JSON.stringify({
|
|
169
|
+
ok: false,
|
|
170
|
+
run_id: runId,
|
|
171
|
+
workspace,
|
|
172
|
+
stopped_at: "doctor",
|
|
173
|
+
failure_layer: doctor.data?.failure_layer || "unknown",
|
|
174
|
+
checks,
|
|
175
|
+
}, null, 2));
|
|
176
|
+
process.exit(1);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
checks.push(runCli(["config", "--json", ...shared], { cwd: workspace }));
|
|
180
|
+
checks.push(runCli(["bootstrap", "--output-dir", outputDir, "--json", ...shared], { cwd: workspace }));
|
|
181
|
+
checks.push(runCli(["feedback-sync", "--output-dir", outputDir, "--json", ...shared], { cwd: workspace }));
|
|
182
|
+
checks.push(runCli(["sync-qaqc", "--output-dir", outputDir, "--json", ...shared], { cwd: workspace }));
|
|
183
|
+
checks.push(runCli(["suggestions", "sync", "--output-dir", outputDir, "--json", ...shared], { cwd: workspace }));
|
|
184
|
+
|
|
185
|
+
const feedbackId = firstFeedbackId(path.join(outputDir, "data", "feedback.yml"));
|
|
186
|
+
if (feedbackId) {
|
|
187
|
+
checks.push(runCli(["feedback", "get", "--feedback-id", feedbackId, "--json", ...shared], { cwd: workspace }));
|
|
188
|
+
checks.push(runCli(["feedback", "history", "--feedback-id", feedbackId, "--json", ...shared], { cwd: workspace }));
|
|
189
|
+
const versionsCheck = runCli(
|
|
190
|
+
["feedback", "prd-versions", "--feedback-id", feedbackId, "--json", ...shared],
|
|
191
|
+
{ cwd: workspace },
|
|
192
|
+
);
|
|
193
|
+
checks.push(versionsCheck);
|
|
194
|
+
if (versionsCheck.ok) {
|
|
195
|
+
const versions = Array.isArray(versionsCheck.data?.versions)
|
|
196
|
+
? versionsCheck.data.versions
|
|
197
|
+
: [];
|
|
198
|
+
const activeVersionId = String(
|
|
199
|
+
versionsCheck.data?.active_prd_version_id || "",
|
|
200
|
+
).trim();
|
|
201
|
+
const targetVersion =
|
|
202
|
+
versions.find((version) => versionIdentifier(version) !== activeVersionId)
|
|
203
|
+
|| versions[0];
|
|
204
|
+
const targetVersionId = versionIdentifier(targetVersion);
|
|
205
|
+
if (targetVersionId) {
|
|
206
|
+
const diffArgs = [
|
|
207
|
+
"feedback",
|
|
208
|
+
"prd-diff",
|
|
209
|
+
"--feedback-id",
|
|
210
|
+
feedbackId,
|
|
211
|
+
"--version-id",
|
|
212
|
+
targetVersionId,
|
|
213
|
+
];
|
|
214
|
+
const documentId = versionDocumentIdentifier(targetVersion);
|
|
215
|
+
if (documentId) diffArgs.push("--document-id", documentId);
|
|
216
|
+
diffArgs.push("--json", ...shared);
|
|
217
|
+
checks.push(runCli(diffArgs, { cwd: workspace }));
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (args["include-query"]) {
|
|
223
|
+
checks.push(runCli([
|
|
224
|
+
"query",
|
|
225
|
+
"Goal: certify Project Assistant query transport. Ask: return the project title in one sentence.",
|
|
226
|
+
"--request-id",
|
|
227
|
+
`cert-read-${runId}`,
|
|
228
|
+
"--json",
|
|
229
|
+
...shared,
|
|
230
|
+
], { cwd: workspace }));
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const failed = checks.filter((check) => !check.ok);
|
|
234
|
+
console.log(JSON.stringify({
|
|
235
|
+
ok: failed.length === 0,
|
|
236
|
+
run_id: runId,
|
|
237
|
+
workspace,
|
|
238
|
+
local_artifacts_only: true,
|
|
239
|
+
live_business_mutations: false,
|
|
240
|
+
checks: checks.map((check) => ({
|
|
241
|
+
id: check.id,
|
|
242
|
+
command: check.command,
|
|
243
|
+
ok: check.ok,
|
|
244
|
+
exit_code: check.exit_code,
|
|
245
|
+
duration_ms: check.duration_ms,
|
|
246
|
+
error: check.error,
|
|
247
|
+
})),
|
|
248
|
+
failed_count: failed.length,
|
|
249
|
+
}, null, 2));
|
|
250
|
+
if (failed.length) process.exit(1);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
try {
|
|
254
|
+
main();
|
|
255
|
+
} catch (error) {
|
|
256
|
+
console.error(JSON.stringify({ ok: false, message: error?.message || String(error) }, null, 2));
|
|
257
|
+
process.exit(1);
|
|
258
|
+
}
|