@mytegroupinc/myte-core 0.0.6 → 0.0.8
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 +25 -0
- package/cli.js +646 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,14 +5,26 @@ Internal implementation package for the `myte` CLI.
|
|
|
5
5
|
Most users should install the unscoped wrapper instead:
|
|
6
6
|
- `npm install myte` then `npx myte bootstrap`
|
|
7
7
|
- `npm install myte` then `npx myte sync-qaqc`
|
|
8
|
+
- `npm install myte` then `npx myte feedback-sync`
|
|
8
9
|
- `npm install myte` then `npx myte query "..." --with-diff`
|
|
9
10
|
- `npm install myte` then `npm exec myte -- query "..." --with-diff`
|
|
11
|
+
- `npm install myte` then `npx myte update-team "Backend deploy completed; QAQC rerun queued."`
|
|
12
|
+
- `npm install myte` then `npx myte update-owner --subject "QAQC progress" --body-file ./updates/owner.md`
|
|
13
|
+
- `npm install myte` then `npx myte update-client --subject "Weekly client update" --body-file ./updates/week-12.md`
|
|
10
14
|
- `npm i -g myte` then `myte bootstrap`
|
|
11
15
|
- `npm i -g myte` then `myte sync-qaqc`
|
|
16
|
+
- `npm i -g myte` then `myte feedback-sync`
|
|
12
17
|
- `npm i -g myte` then `myte query "..." --with-diff`
|
|
18
|
+
- `npm i -g myte` then `myte update-team "Backend deploy completed; QAQC rerun queued."`
|
|
19
|
+
- `npm i -g myte` then `myte update-owner --subject "QAQC progress" --body-file ./updates/owner.md`
|
|
20
|
+
- `npm i -g myte` then `myte update-client --subject "Weekly client update" --body-file ./updates/week-12.md`
|
|
13
21
|
- `npx myte@latest bootstrap`
|
|
14
22
|
- `npx myte@latest sync-qaqc`
|
|
23
|
+
- `npx myte@latest feedback-sync`
|
|
15
24
|
- `npx myte@latest query "..." --with-diff`
|
|
25
|
+
- `npx myte@latest update-team "Backend deploy completed; QAQC rerun queued."`
|
|
26
|
+
- `npx myte@latest update-owner --subject "QAQC progress" --body-file ./updates/owner.md`
|
|
27
|
+
- `npx myte@latest update-client --subject "Weekly client update" --body-file ./updates/week-12.md`
|
|
16
28
|
- `npm install myte` then `npx myte create-prd ./drafts/auth-prd.md`
|
|
17
29
|
- `cat ./drafts/auth-prd.md | npx myte create-prd --stdin`
|
|
18
30
|
|
|
@@ -35,7 +47,16 @@ Notes:
|
|
|
35
47
|
- `sync-qaqc` writes active mission QAQC cards to `MyteCommandCenter/data/qaqc/active-missions` and refreshes matching `MyteCommandCenter/data/missions` cards.
|
|
36
48
|
- `sync-qaqc` only exports active `Todo` / `In Progress` missions plus a public QAQC summary and sanitized latest batch metadata.
|
|
37
49
|
- `sync-qaqc` removes previously QAQC-managed mission files from `MyteCommandCenter/data/missions` once they leave the active set.
|
|
50
|
+
- `feedback-sync` writes public feedback cards under `MyteCommandCenter/data/feedback/items`.
|
|
51
|
+
- `feedback-sync` writes readable PRD copies under `MyteCommandCenter/data/feedback/prds` when PRD text exists.
|
|
52
|
+
- `feedback-sync` fully replaces the feedback-owned sync folders to avoid stale local feedback noise.
|
|
38
53
|
- `create-prd` is a deterministic PRD upload path, not an LLM generation command.
|
|
54
|
+
- `update-team` creates a project comment through `/api/project-assistant/project-comment`.
|
|
55
|
+
- `update-owner` sends a direct owner email through `/api/project-assistant/update-owner`.
|
|
56
|
+
- `update-owner` requires `--subject` plus body markdown from `--body-markdown`, `--body-file`, positional input, or `--stdin`.
|
|
57
|
+
- `update-client` creates a client update draft through `/api/project-assistant/client-update-drafts`.
|
|
58
|
+
- `update-client` requires `--subject` plus body markdown from `--body-markdown`, `--body-file`, positional input, or `--stdin`.
|
|
59
|
+
- `update-client` accepts optional `--target-contact-id` repeats or `--target-contact-ids <id1,id2>`.
|
|
39
60
|
- `--with-diff` only searches repo folders whose names match the project repo names configured in Myte.
|
|
40
61
|
- `--with-diff` includes per-repo diagnostics in `print-context` payload:
|
|
41
62
|
- missing repo directories
|
|
@@ -54,9 +75,13 @@ Deterministic `create-prd` contract:
|
|
|
54
75
|
Examples:
|
|
55
76
|
- `npx myte bootstrap`
|
|
56
77
|
- `npx myte sync-qaqc`
|
|
78
|
+
- `npx myte feedback-sync`
|
|
57
79
|
- `npx myte bootstrap --dry-run --json`
|
|
58
80
|
- `npx myte sync-qaqc --dry-run --json`
|
|
59
81
|
- `npx myte create-prd ./drafts/auth-prd.md --description "Short card summary"`
|
|
60
82
|
- `npx myte create-prd ./drafts/auth-prd.md --print-context`
|
|
83
|
+
- `npx myte update-team "Backend deploy completed; QAQC rerun queued."`
|
|
84
|
+
- `npx myte update-owner --subject "QAQC progress" --body-file ./updates/owner.md`
|
|
85
|
+
- `npx myte update-client --subject "Weekly client update" --body-file ./updates/week-12.md`
|
|
61
86
|
|
|
62
87
|
This package is published under the org scope for governance; the public `myte` wrapper delegates here.
|
package/cli.js
CHANGED
|
@@ -49,7 +49,25 @@ function loadEnv() {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
function splitCommand(argv) {
|
|
52
|
-
const known = new Set([
|
|
52
|
+
const known = new Set([
|
|
53
|
+
"query",
|
|
54
|
+
"ask",
|
|
55
|
+
"chat",
|
|
56
|
+
"config",
|
|
57
|
+
"bootstrap",
|
|
58
|
+
"sync-qaqc",
|
|
59
|
+
"qaqc-sync",
|
|
60
|
+
"create-prd",
|
|
61
|
+
"add-prd",
|
|
62
|
+
"prd",
|
|
63
|
+
"update-team",
|
|
64
|
+
"update-owner",
|
|
65
|
+
"update-client",
|
|
66
|
+
"feedback-sync",
|
|
67
|
+
"help",
|
|
68
|
+
"--help",
|
|
69
|
+
"-h",
|
|
70
|
+
]);
|
|
53
71
|
const first = argv[0];
|
|
54
72
|
if (first && known.has(first)) {
|
|
55
73
|
const cmd = first === "--help" || first === "-h" ? "help" : first;
|
|
@@ -62,8 +80,28 @@ function parseArgs(argv) {
|
|
|
62
80
|
try {
|
|
63
81
|
// eslint-disable-next-line global-require
|
|
64
82
|
return require("minimist")(argv, {
|
|
65
|
-
boolean: ["with-diff", "diff", "print-context", "dry-run", "fetch", "json", "stdin"],
|
|
66
|
-
string: [
|
|
83
|
+
boolean: ["with-diff", "diff", "print-context", "dry-run", "fetch", "json", "stdin", "with-prd-text"],
|
|
84
|
+
string: [
|
|
85
|
+
"query",
|
|
86
|
+
"q",
|
|
87
|
+
"context",
|
|
88
|
+
"ctx",
|
|
89
|
+
"base-url",
|
|
90
|
+
"timeout-ms",
|
|
91
|
+
"diff-limit",
|
|
92
|
+
"title",
|
|
93
|
+
"description",
|
|
94
|
+
"feedback-text",
|
|
95
|
+
"output-dir",
|
|
96
|
+
"content",
|
|
97
|
+
"subject",
|
|
98
|
+
"body-markdown",
|
|
99
|
+
"body-file",
|
|
100
|
+
"target-contact-id",
|
|
101
|
+
"target-contact-ids",
|
|
102
|
+
"status",
|
|
103
|
+
"source",
|
|
104
|
+
],
|
|
67
105
|
alias: {
|
|
68
106
|
q: "query",
|
|
69
107
|
d: "with-diff",
|
|
@@ -118,10 +156,16 @@ function printHelp() {
|
|
|
118
156
|
" myte config [--json]",
|
|
119
157
|
" myte bootstrap [--output-dir ./MyteCommandCenter] [--json]",
|
|
120
158
|
" myte sync-qaqc [--output-dir ./MyteCommandCenter] [--json]",
|
|
159
|
+
" myte update-team \"<content>\" [--json]",
|
|
160
|
+
" myte update-owner --subject \"<text>\" [--body-markdown \"...\"] [--body-file ./update.md] [--json]",
|
|
161
|
+
" myte update-client --subject \"<text>\" [--body-markdown \"...\"] [--body-file ./update.md] [--target-contact-ids <id1,id2>] [--json]",
|
|
162
|
+
" myte feedback-sync [--status Pending] [--source User] [--output-dir ./MyteCommandCenter] [--json]",
|
|
121
163
|
" myte chat",
|
|
122
164
|
" myte create-prd <file.md> [--json] [--title \"...\"] [--description \"...\"]",
|
|
123
165
|
" myte add-prd <file.md> [--json]",
|
|
124
166
|
" cat file.md | myte create-prd --stdin [--title \"...\"] [--description \"...\"]",
|
|
167
|
+
" cat update.md | myte update-owner --stdin --subject \"Owner update\"",
|
|
168
|
+
" cat update.md | myte update-client --stdin --subject \"Weekly client update\"",
|
|
125
169
|
"",
|
|
126
170
|
"Run forms:",
|
|
127
171
|
" npm install myte then npx myte query \"...\" --with-diff",
|
|
@@ -149,15 +193,43 @@ function printHelp() {
|
|
|
149
193
|
" - Description source: myte-kanban.description or --description",
|
|
150
194
|
" - PRD DOCX content: the markdown body is stored verbatim",
|
|
151
195
|
"",
|
|
196
|
+
"update-team contract:",
|
|
197
|
+
" - Creates a project team comment through /api/project-assistant/project-comment",
|
|
198
|
+
" - Required: content (inline, --content, or --stdin)",
|
|
199
|
+
"",
|
|
200
|
+
"update-owner contract:",
|
|
201
|
+
" - Sends a direct owner email through /api/project-assistant/update-owner",
|
|
202
|
+
" - Required: --subject and body markdown (via --body-markdown, --body-file, positional file/text, or --stdin)",
|
|
203
|
+
" - Uses Myte SMTP, resolves the owner from the project, and stores a durable send record",
|
|
204
|
+
"",
|
|
205
|
+
"update-client contract:",
|
|
206
|
+
" - Creates a client update draft through /api/project-assistant/client-update-drafts",
|
|
207
|
+
" - Required: --subject and body markdown (via --body-markdown, --body-file, positional file/text, or --stdin)",
|
|
208
|
+
" - Optional: --target-contact-id <id> (repeatable) or --target-contact-ids <id1,id2>",
|
|
209
|
+
"",
|
|
210
|
+
"feedback-sync contract:",
|
|
211
|
+
" - Runs from the wrapper root that contains the project's configured repo folders",
|
|
212
|
+
" - Writes project feedback cards under MyteCommandCenter/data/feedback/items",
|
|
213
|
+
" - Writes PRD text copies under MyteCommandCenter/data/feedback/prds when available",
|
|
214
|
+
"",
|
|
152
215
|
"Options:",
|
|
153
216
|
" --with-diff Include deterministic git diffs (project-scoped)",
|
|
154
217
|
" --diff-limit <chars> Truncate diff context to N chars (default: 200000)",
|
|
155
218
|
" --timeout-ms <ms> Request timeout (default: 300000)",
|
|
156
219
|
" --base-url <url> API base (default: https://api.myte.dev)",
|
|
157
220
|
" --output-dir <path> Bootstrap output directory (default: <wrapper-root>/MyteCommandCenter)",
|
|
158
|
-
" --stdin Read
|
|
221
|
+
" --stdin Read supported command content from stdin instead of inline text or a file path",
|
|
159
222
|
" --title <text> Override PRD title for raw markdown uploads",
|
|
160
223
|
" --description <text> Set feedback description/card summary for raw markdown uploads",
|
|
224
|
+
" --content <text> Team update content for update-team",
|
|
225
|
+
" --subject <text> Subject for update-owner or update-client",
|
|
226
|
+
" --body-markdown <md> Markdown body for update-owner or update-client",
|
|
227
|
+
" --body-file <path> Read update-owner or update-client markdown body from a file",
|
|
228
|
+
" --target-contact-id Add one client contact ObjectId (repeatable)",
|
|
229
|
+
" --target-contact-ids Comma-separated client contact ObjectIds",
|
|
230
|
+
" --status <value> Feedback status filter for feedback-sync (default: Pending)",
|
|
231
|
+
" --source <value> Feedback source filter for feedback-sync",
|
|
232
|
+
" --with-prd-text Include extracted PRD text in feedback-sync (default: on)",
|
|
161
233
|
" --print-context Print JSON payload and exit (no query call)",
|
|
162
234
|
" --no-fetch Don't git fetch origin main/master before diff",
|
|
163
235
|
"",
|
|
@@ -166,6 +238,11 @@ function printHelp() {
|
|
|
166
238
|
" myte bootstrap",
|
|
167
239
|
" myte bootstrap --output-dir ./MyteCommandCenter",
|
|
168
240
|
" myte sync-qaqc",
|
|
241
|
+
" myte update-team \"Backend deploy completed; QAQC rerun queued.\"",
|
|
242
|
+
" myte update-owner --subject \"QAQC progress\" --body-file ./updates/owner.md",
|
|
243
|
+
" myte update-client --subject \"Weekly client update\" --body-file ./updates/week-12.md",
|
|
244
|
+
" myte feedback-sync --status Pending --source User",
|
|
245
|
+
" myte update-client --subject \"Weekly client update\" --body-markdown \"## Progress\\n- Login complete\" --target-contact-ids 507f1f77bcf86cd799439011,507f1f77bcf86cd799439012",
|
|
169
246
|
" myte create-prd ./drafts/auth-prd.md --description \"Short card summary\"",
|
|
170
247
|
" cat ./drafts/auth-prd.md | myte create-prd --stdin",
|
|
171
248
|
" myte config",
|
|
@@ -202,6 +279,148 @@ async function readStdinText() {
|
|
|
202
279
|
});
|
|
203
280
|
}
|
|
204
281
|
|
|
282
|
+
function firstNonEmptyString(...values) {
|
|
283
|
+
for (const value of values) {
|
|
284
|
+
if (value === undefined || value === null) continue;
|
|
285
|
+
if (Array.isArray(value)) {
|
|
286
|
+
const nested = firstNonEmptyString(...value);
|
|
287
|
+
if (nested) return nested;
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
const text = String(value).trim();
|
|
291
|
+
if (text) return text;
|
|
292
|
+
}
|
|
293
|
+
return "";
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function toStringArray(value) {
|
|
297
|
+
if (value === undefined || value === null) return [];
|
|
298
|
+
return Array.isArray(value) ? value.flatMap((item) => toStringArray(item)) : [String(value)];
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function parseCsvValues(...values) {
|
|
302
|
+
return values
|
|
303
|
+
.flatMap((value) => toStringArray(value))
|
|
304
|
+
.flatMap((value) => value.split(","))
|
|
305
|
+
.map((value) => value.trim())
|
|
306
|
+
.filter(Boolean);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function dedupeStrings(values) {
|
|
310
|
+
const seen = new Set();
|
|
311
|
+
const unique = [];
|
|
312
|
+
for (const value of values) {
|
|
313
|
+
const normalized = String(value || "").trim();
|
|
314
|
+
if (!normalized || seen.has(normalized)) continue;
|
|
315
|
+
seen.add(normalized);
|
|
316
|
+
unique.push(normalized);
|
|
317
|
+
}
|
|
318
|
+
return unique;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function resolveTimeoutMs(args) {
|
|
322
|
+
const timeoutRaw = args["timeout-ms"] || args.timeoutMs || args.timeout_ms;
|
|
323
|
+
const timeoutParsed = timeoutRaw !== undefined ? Number(timeoutRaw) : 300_000;
|
|
324
|
+
return Number.isFinite(timeoutParsed) ? timeoutParsed : 300_000;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function resolveApiBase(args) {
|
|
328
|
+
const baseRaw =
|
|
329
|
+
args["base-url"] || args.baseUrl || args.base_url || process.env.MYTE_API_BASE || DEFAULT_API_BASE;
|
|
330
|
+
return normalizeApiBase(baseRaw);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function getProjectApiKey() {
|
|
334
|
+
return (process.env.MYTE_API_KEY || process.env.MYTE_PROJECT_API_KEY || "").trim();
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function resolveInputFile(candidatePath, label) {
|
|
338
|
+
const resolved = String(candidatePath || "").trim();
|
|
339
|
+
if (!resolved) return null;
|
|
340
|
+
const absPath = path.resolve(process.cwd(), resolved);
|
|
341
|
+
if (!fs.existsSync(absPath) || !fs.statSync(absPath).isFile()) {
|
|
342
|
+
console.error(`${label} file not found: ${absPath}`);
|
|
343
|
+
process.exit(1);
|
|
344
|
+
}
|
|
345
|
+
return absPath;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
async function resolveTeamUpdateContent(args) {
|
|
349
|
+
const inlineContent = firstNonEmptyString(args.content, Array.isArray(args._) ? args._.join(" ") : args._);
|
|
350
|
+
const useStdin = Boolean(args.stdin || (!process.stdin.isTTY && !inlineContent));
|
|
351
|
+
if (useStdin) {
|
|
352
|
+
const stdinContent = String((await readStdinText()) || "").trim();
|
|
353
|
+
if (!stdinContent) {
|
|
354
|
+
console.error("Team update content is empty.");
|
|
355
|
+
process.exit(1);
|
|
356
|
+
}
|
|
357
|
+
return stdinContent;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const content = String(inlineContent || "").trim();
|
|
361
|
+
if (!content) {
|
|
362
|
+
console.error("Missing team update content.");
|
|
363
|
+
printHelp();
|
|
364
|
+
process.exit(1);
|
|
365
|
+
}
|
|
366
|
+
return content;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
async function resolveClientUpdateBody(args) {
|
|
370
|
+
const inlineBody = firstNonEmptyString(
|
|
371
|
+
args["body-markdown"],
|
|
372
|
+
args.bodyMarkdown,
|
|
373
|
+
args.body_markdown
|
|
374
|
+
);
|
|
375
|
+
if (inlineBody) return inlineBody;
|
|
376
|
+
|
|
377
|
+
const explicitFile = firstNonEmptyString(args["body-file"], args.bodyFile, args.body_file);
|
|
378
|
+
const positionalInput = firstNonEmptyString(Array.isArray(args._) ? args._.join(" ") : args._);
|
|
379
|
+
const useStdin = Boolean(args.stdin || (!process.stdin.isTTY && !explicitFile && !positionalInput));
|
|
380
|
+
if (useStdin) {
|
|
381
|
+
const stdinBody = String((await readStdinText()) || "").trim();
|
|
382
|
+
if (!stdinBody) {
|
|
383
|
+
console.error("Client update body_markdown is empty.");
|
|
384
|
+
process.exit(1);
|
|
385
|
+
}
|
|
386
|
+
return stdinBody;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
const fileCandidate = explicitFile || (positionalInput && fs.existsSync(path.resolve(process.cwd(), positionalInput)) ? positionalInput : "");
|
|
390
|
+
if (fileCandidate) {
|
|
391
|
+
const absPath = resolveInputFile(fileCandidate, "Client update body");
|
|
392
|
+
return String(fs.readFileSync(absPath, "utf8") || "").trim();
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
if (positionalInput) return positionalInput;
|
|
396
|
+
|
|
397
|
+
console.error("Missing client update body_markdown.");
|
|
398
|
+
printHelp();
|
|
399
|
+
process.exit(1);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
async function resolveOwnerUpdateBody(args) {
|
|
403
|
+
const body = await resolveClientUpdateBody(args);
|
|
404
|
+
if (!body) {
|
|
405
|
+
console.error("Owner update body_markdown is empty.");
|
|
406
|
+
process.exit(1);
|
|
407
|
+
}
|
|
408
|
+
return body;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function resolveTargetContactIds(args) {
|
|
412
|
+
return dedupeStrings(
|
|
413
|
+
parseCsvValues(
|
|
414
|
+
args["target-contact-id"],
|
|
415
|
+
args.targetContactId,
|
|
416
|
+
args.target_contact_id,
|
|
417
|
+
args["target-contact-ids"],
|
|
418
|
+
args.targetContactIds,
|
|
419
|
+
args.target_contact_ids
|
|
420
|
+
)
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
|
|
205
424
|
async function getFetch() {
|
|
206
425
|
if (typeof fetch !== "undefined") return fetch;
|
|
207
426
|
const mod = await import("node-fetch");
|
|
@@ -763,6 +982,33 @@ async function fetchQaqcSyncSnapshot({ apiBase, key, timeoutMs }) {
|
|
|
763
982
|
return body.data || {};
|
|
764
983
|
}
|
|
765
984
|
|
|
985
|
+
async function fetchFeedbackSyncSnapshot({ apiBase, key, timeoutMs, filters = {} }) {
|
|
986
|
+
const fetchFn = await getFetch();
|
|
987
|
+
const url = new URL(`${apiBase}/project-assistant/feedback-sync`);
|
|
988
|
+
if (filters.status) url.searchParams.set("status", String(filters.status));
|
|
989
|
+
if (filters.source) url.searchParams.set("source", String(filters.source));
|
|
990
|
+
if (filters.includePrdText !== undefined) {
|
|
991
|
+
url.searchParams.set("include_prd_text", filters.includePrdText ? "true" : "false");
|
|
992
|
+
}
|
|
993
|
+
const { resp, body } = await fetchJsonWithTimeout(
|
|
994
|
+
fetchFn,
|
|
995
|
+
url.toString(),
|
|
996
|
+
{
|
|
997
|
+
method: "GET",
|
|
998
|
+
headers: { Authorization: `Bearer ${key}` },
|
|
999
|
+
},
|
|
1000
|
+
timeoutMs
|
|
1001
|
+
);
|
|
1002
|
+
|
|
1003
|
+
if (!resp.ok || body.status !== "success") {
|
|
1004
|
+
const msg = body?.message || `Feedback sync request failed (${resp.status})`;
|
|
1005
|
+
const err = new Error(msg);
|
|
1006
|
+
err.status = resp.status;
|
|
1007
|
+
throw err;
|
|
1008
|
+
}
|
|
1009
|
+
return body.data || {};
|
|
1010
|
+
}
|
|
1011
|
+
|
|
766
1012
|
async function callAssistantQuery({ apiBase, key, payload, timeoutMs, endpoint = "/project-assistant/query" }) {
|
|
767
1013
|
const fetchFn = await getFetch();
|
|
768
1014
|
const url = `${apiBase}${endpoint}`;
|
|
@@ -789,6 +1035,206 @@ async function callAssistantQuery({ apiBase, key, payload, timeoutMs, endpoint =
|
|
|
789
1035
|
return body.data || {};
|
|
790
1036
|
}
|
|
791
1037
|
|
|
1038
|
+
function formatTargetContacts(contacts) {
|
|
1039
|
+
const items = Array.isArray(contacts) ? contacts : [];
|
|
1040
|
+
const formatted = items
|
|
1041
|
+
.map((contact) => {
|
|
1042
|
+
const name = String(contact?.name || "").trim();
|
|
1043
|
+
const email = String(contact?.email || "").trim();
|
|
1044
|
+
if (name && email) return `${name} <${email}>`;
|
|
1045
|
+
return name || email || String(contact?.contact_id || "").trim();
|
|
1046
|
+
})
|
|
1047
|
+
.filter(Boolean);
|
|
1048
|
+
return formatted.join(", ");
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
async function runUpdateTeam(args) {
|
|
1052
|
+
const key = getProjectApiKey();
|
|
1053
|
+
if (!key) {
|
|
1054
|
+
console.error("Missing MYTE_API_KEY (project key) in environment/.env");
|
|
1055
|
+
process.exit(1);
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
const payload = {
|
|
1059
|
+
content: await resolveTeamUpdateContent(args),
|
|
1060
|
+
};
|
|
1061
|
+
|
|
1062
|
+
if (args["print-context"] || args.printContext || args["dry-run"] || args.dryRun) {
|
|
1063
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
1064
|
+
return;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
const timeoutMs = resolveTimeoutMs(args);
|
|
1068
|
+
const apiBase = resolveApiBase(args);
|
|
1069
|
+
|
|
1070
|
+
let data;
|
|
1071
|
+
try {
|
|
1072
|
+
data = await callAssistantQuery({
|
|
1073
|
+
apiBase,
|
|
1074
|
+
key,
|
|
1075
|
+
payload,
|
|
1076
|
+
timeoutMs,
|
|
1077
|
+
endpoint: "/project-assistant/project-comment",
|
|
1078
|
+
});
|
|
1079
|
+
} catch (err) {
|
|
1080
|
+
if (err?.name === "AbortError") {
|
|
1081
|
+
console.error(`Request timed out after ${timeoutMs}ms`);
|
|
1082
|
+
} else {
|
|
1083
|
+
console.error("Team update failed:", err?.message || err);
|
|
1084
|
+
}
|
|
1085
|
+
process.exit(1);
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
if (args.json) {
|
|
1089
|
+
console.log(JSON.stringify(data, null, 2));
|
|
1090
|
+
return;
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
if (data.comment_id) console.log(`Comment ID: ${data.comment_id}`);
|
|
1094
|
+
if (data.project_id) console.log(`Project ID: ${data.project_id}`);
|
|
1095
|
+
if (data.user?.name) console.log(`Author: ${data.user.name}`);
|
|
1096
|
+
if (data.created_at) console.log(`Created At: ${data.created_at}`);
|
|
1097
|
+
if (data.content) {
|
|
1098
|
+
console.log("Content:");
|
|
1099
|
+
console.log(data.content);
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
async function runUpdateOwner(args) {
|
|
1104
|
+
const key = getProjectApiKey();
|
|
1105
|
+
if (!key) {
|
|
1106
|
+
console.error("Missing MYTE_API_KEY (project key) in environment/.env");
|
|
1107
|
+
process.exit(1);
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
const subject = firstNonEmptyString(args.subject);
|
|
1111
|
+
if (!subject) {
|
|
1112
|
+
console.error("Missing --subject for owner update.");
|
|
1113
|
+
printHelp();
|
|
1114
|
+
process.exit(1);
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
const payload = {
|
|
1118
|
+
subject,
|
|
1119
|
+
body_markdown: await resolveOwnerUpdateBody(args),
|
|
1120
|
+
};
|
|
1121
|
+
|
|
1122
|
+
if (args["print-context"] || args.printContext || args["dry-run"] || args.dryRun) {
|
|
1123
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
1124
|
+
return;
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
const timeoutMs = resolveTimeoutMs(args);
|
|
1128
|
+
const apiBase = resolveApiBase(args);
|
|
1129
|
+
|
|
1130
|
+
let data;
|
|
1131
|
+
try {
|
|
1132
|
+
data = await callAssistantQuery({
|
|
1133
|
+
apiBase,
|
|
1134
|
+
key,
|
|
1135
|
+
payload,
|
|
1136
|
+
timeoutMs,
|
|
1137
|
+
endpoint: "/project-assistant/update-owner",
|
|
1138
|
+
});
|
|
1139
|
+
} catch (err) {
|
|
1140
|
+
if (err?.name === "AbortError") {
|
|
1141
|
+
console.error(`Request timed out after ${timeoutMs}ms`);
|
|
1142
|
+
} else {
|
|
1143
|
+
console.error("Owner update failed:", err?.message || err);
|
|
1144
|
+
}
|
|
1145
|
+
process.exit(1);
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
if (args.json) {
|
|
1149
|
+
console.log(JSON.stringify(data, null, 2));
|
|
1150
|
+
return;
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
if (data.update_id) console.log(`Update ID: ${data.update_id}`);
|
|
1154
|
+
if (data.project_title) console.log(`Project: ${data.project_title}`);
|
|
1155
|
+
if (data.project_id) console.log(`Project ID: ${data.project_id}`);
|
|
1156
|
+
if (data.status) console.log(`Status: ${data.status}`);
|
|
1157
|
+
if (data.subject) console.log(`Subject: ${data.subject}`);
|
|
1158
|
+
if (data.owner_name || data.owner_email) {
|
|
1159
|
+
console.log(`Owner: ${data.owner_name || data.owner_email}${data.owner_email && data.owner_name ? ` <${data.owner_email}>` : ""}`);
|
|
1160
|
+
}
|
|
1161
|
+
if (data.sender_name || data.sender_email) {
|
|
1162
|
+
console.log(`Sender: ${data.sender_name || data.sender_email}${data.sender_email && data.sender_name ? ` <${data.sender_email}>` : ""}`);
|
|
1163
|
+
}
|
|
1164
|
+
if (data.sent_at) console.log(`Sent At: ${data.sent_at}`);
|
|
1165
|
+
if (data.snippet) {
|
|
1166
|
+
console.log("Snippet:");
|
|
1167
|
+
console.log(data.snippet);
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
async function runUpdateClient(args) {
|
|
1172
|
+
const key = getProjectApiKey();
|
|
1173
|
+
if (!key) {
|
|
1174
|
+
console.error("Missing MYTE_API_KEY (project key) in environment/.env");
|
|
1175
|
+
process.exit(1);
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
const subject = firstNonEmptyString(args.subject);
|
|
1179
|
+
if (!subject) {
|
|
1180
|
+
console.error("Missing --subject for client update.");
|
|
1181
|
+
printHelp();
|
|
1182
|
+
process.exit(1);
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
const payload = {
|
|
1186
|
+
subject,
|
|
1187
|
+
body_markdown: await resolveClientUpdateBody(args),
|
|
1188
|
+
target_contact_ids: resolveTargetContactIds(args),
|
|
1189
|
+
};
|
|
1190
|
+
|
|
1191
|
+
if (args["print-context"] || args.printContext || args["dry-run"] || args.dryRun) {
|
|
1192
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
const timeoutMs = resolveTimeoutMs(args);
|
|
1197
|
+
const apiBase = resolveApiBase(args);
|
|
1198
|
+
|
|
1199
|
+
let data;
|
|
1200
|
+
try {
|
|
1201
|
+
data = await callAssistantQuery({
|
|
1202
|
+
apiBase,
|
|
1203
|
+
key,
|
|
1204
|
+
payload,
|
|
1205
|
+
timeoutMs,
|
|
1206
|
+
endpoint: "/project-assistant/client-update-drafts",
|
|
1207
|
+
});
|
|
1208
|
+
} catch (err) {
|
|
1209
|
+
if (err?.name === "AbortError") {
|
|
1210
|
+
console.error(`Request timed out after ${timeoutMs}ms`);
|
|
1211
|
+
} else {
|
|
1212
|
+
console.error("Client update draft failed:", err?.message || err);
|
|
1213
|
+
}
|
|
1214
|
+
process.exit(1);
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
if (args.json) {
|
|
1218
|
+
console.log(JSON.stringify(data, null, 2));
|
|
1219
|
+
return;
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
if (data.draft_id) console.log(`Draft ID: ${data.draft_id}`);
|
|
1223
|
+
if (data.project_title) console.log(`Project: ${data.project_title}`);
|
|
1224
|
+
if (data.project_id) console.log(`Project ID: ${data.project_id}`);
|
|
1225
|
+
if (data.status) console.log(`Status: ${data.status}`);
|
|
1226
|
+
if (data.subject) console.log(`Subject: ${data.subject}`);
|
|
1227
|
+
if (data.created_by_name) console.log(`Author: ${data.created_by_name}`);
|
|
1228
|
+
const targets = formatTargetContacts(data.target_contacts);
|
|
1229
|
+
if (targets) console.log(`Targets: ${targets}`);
|
|
1230
|
+
if (data.created_at) console.log(`Created At: ${data.created_at}`);
|
|
1231
|
+
if (data.updated_at) console.log(`Updated At: ${data.updated_at}`);
|
|
1232
|
+
if (data.snippet) {
|
|
1233
|
+
console.log("Snippet:");
|
|
1234
|
+
console.log(data.snippet);
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
|
|
792
1238
|
function ensureDir(dirPath) {
|
|
793
1239
|
fs.mkdirSync(dirPath, { recursive: true });
|
|
794
1240
|
}
|
|
@@ -805,6 +1251,20 @@ function clearYamlDirectory(dirPath) {
|
|
|
805
1251
|
}
|
|
806
1252
|
}
|
|
807
1253
|
|
|
1254
|
+
function clearFileDirectory(dirPath, extensions) {
|
|
1255
|
+
const normalized = new Set((Array.isArray(extensions) ? extensions : []).map((ext) => String(ext || "").toLowerCase()));
|
|
1256
|
+
if (!fs.existsSync(dirPath)) {
|
|
1257
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
1258
|
+
return;
|
|
1259
|
+
}
|
|
1260
|
+
for (const entry of fs.readdirSync(dirPath, { withFileTypes: true })) {
|
|
1261
|
+
if (!entry.isFile()) continue;
|
|
1262
|
+
const ext = path.extname(entry.name).toLowerCase();
|
|
1263
|
+
if (normalized.size && !normalized.has(ext)) continue;
|
|
1264
|
+
fs.rmSync(path.join(dirPath, entry.name), { force: true });
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
|
|
808
1268
|
function stableItemId(item, keys, fallback) {
|
|
809
1269
|
for (const key of keys) {
|
|
810
1270
|
const value = String(item?.[key] || "").trim();
|
|
@@ -829,6 +1289,11 @@ function writeJsonFile(filePath, value) {
|
|
|
829
1289
|
fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
|
|
830
1290
|
}
|
|
831
1291
|
|
|
1292
|
+
function writeTextFile(filePath, value) {
|
|
1293
|
+
ensureDir(path.dirname(filePath));
|
|
1294
|
+
fs.writeFileSync(filePath, String(value || ""), "utf8");
|
|
1295
|
+
}
|
|
1296
|
+
|
|
832
1297
|
function readJsonFile(filePath) {
|
|
833
1298
|
if (!fs.existsSync(filePath) || !fs.statSync(filePath).isFile()) return null;
|
|
834
1299
|
try {
|
|
@@ -1004,6 +1469,66 @@ function writeQaqcSnapshot({ snapshot, wrapperRoot, outputDir }) {
|
|
|
1004
1469
|
};
|
|
1005
1470
|
}
|
|
1006
1471
|
|
|
1472
|
+
function writeFeedbackSnapshot({ snapshot, wrapperRoot, outputDir }) {
|
|
1473
|
+
const targetRoot = outputDir
|
|
1474
|
+
? path.resolve(process.cwd(), String(outputDir))
|
|
1475
|
+
: path.join(wrapperRoot, "MyteCommandCenter");
|
|
1476
|
+
const dataRoot = path.join(targetRoot, "data");
|
|
1477
|
+
const feedbackRoot = path.join(dataRoot, "feedback");
|
|
1478
|
+
const itemsDir = path.join(feedbackRoot, "items");
|
|
1479
|
+
const prdsDir = path.join(feedbackRoot, "prds");
|
|
1480
|
+
|
|
1481
|
+
ensureDir(dataRoot);
|
|
1482
|
+
ensureDir(feedbackRoot);
|
|
1483
|
+
clearYamlDirectory(itemsDir);
|
|
1484
|
+
clearFileDirectory(prdsDir, [".md"]);
|
|
1485
|
+
|
|
1486
|
+
const items = Array.isArray(snapshot.items) ? snapshot.items.map((item) => scrubBootstrapValue(item)) : [];
|
|
1487
|
+
const itemIds = [];
|
|
1488
|
+
let prdCount = 0;
|
|
1489
|
+
|
|
1490
|
+
if (snapshot.project && typeof snapshot.project === "object") {
|
|
1491
|
+
writeYamlFile(path.join(dataRoot, "project.yml"), scrubBootstrapValue(snapshot.project));
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
items.forEach((item, index) => {
|
|
1495
|
+
const feedbackId = stableItemId(item, ["feedback_id", "id"], `F${String(index + 1).padStart(3, "0")}`);
|
|
1496
|
+
itemIds.push(feedbackId);
|
|
1497
|
+
const card = scrubBootstrapValue(item);
|
|
1498
|
+
const prdText = String(card.prd_text || "").trim();
|
|
1499
|
+
if (prdText) {
|
|
1500
|
+
delete card.prd_text;
|
|
1501
|
+
card.prd_file = `prds/${feedbackId}.md`;
|
|
1502
|
+
writeTextFile(path.join(prdsDir, `${feedbackId}.md`), `${prdText}\n`);
|
|
1503
|
+
prdCount += 1;
|
|
1504
|
+
}
|
|
1505
|
+
writeYamlFile(path.join(itemsDir, `${feedbackId}.yml`), card);
|
|
1506
|
+
});
|
|
1507
|
+
|
|
1508
|
+
const manifest = {
|
|
1509
|
+
schema_version: snapshot.schema_version || 1,
|
|
1510
|
+
generated_at: snapshot.generated_at || null,
|
|
1511
|
+
snapshot_hash: snapshot.snapshot_hash || null,
|
|
1512
|
+
project: snapshot.project ? scrubBootstrapValue(snapshot.project) : null,
|
|
1513
|
+
repo_names: Array.isArray(snapshot.repo_names) ? snapshot.repo_names : [],
|
|
1514
|
+
filters: snapshot.filters && typeof snapshot.filters === "object" ? scrubBootstrapValue(snapshot.filters) : {},
|
|
1515
|
+
item_ids: itemIds,
|
|
1516
|
+
counts: snapshot.counts && typeof snapshot.counts === "object"
|
|
1517
|
+
? scrubBootstrapValue(snapshot.counts)
|
|
1518
|
+
: { total_feedback: items.length, with_prd_text: prdCount },
|
|
1519
|
+
};
|
|
1520
|
+
if (snapshot.pagination && typeof snapshot.pagination === "object") {
|
|
1521
|
+
manifest.pagination = scrubBootstrapValue(snapshot.pagination);
|
|
1522
|
+
}
|
|
1523
|
+
writeJsonFile(path.join(feedbackRoot, "manifest.json"), manifest);
|
|
1524
|
+
|
|
1525
|
+
return {
|
|
1526
|
+
targetRoot,
|
|
1527
|
+
dataRoot,
|
|
1528
|
+
manifest,
|
|
1529
|
+
};
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1007
1532
|
async function runCreatePrd(args) {
|
|
1008
1533
|
const key = (process.env.MYTE_API_KEY || process.env.MYTE_PROJECT_API_KEY || "").trim();
|
|
1009
1534
|
if (!key) {
|
|
@@ -1347,6 +1872,103 @@ async function runSyncQaqc(args) {
|
|
|
1347
1872
|
console.log(`Snapshot: ${summary.snapshot_hash || "n/a"}`);
|
|
1348
1873
|
}
|
|
1349
1874
|
|
|
1875
|
+
async function runFeedbackSync(args) {
|
|
1876
|
+
const key = getProjectApiKey();
|
|
1877
|
+
if (!key) {
|
|
1878
|
+
console.error("Missing MYTE_API_KEY (project key) in environment/.env");
|
|
1879
|
+
process.exit(1);
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1882
|
+
const timeoutMs = resolveTimeoutMs(args);
|
|
1883
|
+
const apiBase = resolveApiBase(args);
|
|
1884
|
+
const includePrdText = args["with-prd-text"] !== undefined
|
|
1885
|
+
? Boolean(args["with-prd-text"])
|
|
1886
|
+
: args.withPrdText !== undefined
|
|
1887
|
+
? Boolean(args.withPrdText)
|
|
1888
|
+
: true;
|
|
1889
|
+
const filters = {
|
|
1890
|
+
status: firstNonEmptyString(args.status) || "Pending",
|
|
1891
|
+
source: firstNonEmptyString(args.source) || "",
|
|
1892
|
+
includePrdText,
|
|
1893
|
+
};
|
|
1894
|
+
|
|
1895
|
+
let snapshot;
|
|
1896
|
+
try {
|
|
1897
|
+
snapshot = await fetchFeedbackSyncSnapshot({ apiBase, key, timeoutMs, filters });
|
|
1898
|
+
} catch (err) {
|
|
1899
|
+
console.error("Failed to fetch feedback sync snapshot:", err?.message || err);
|
|
1900
|
+
process.exit(1);
|
|
1901
|
+
}
|
|
1902
|
+
|
|
1903
|
+
if (args["print-context"] || args.printContext) {
|
|
1904
|
+
console.log(JSON.stringify(snapshot, null, 2));
|
|
1905
|
+
return;
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
let resolved;
|
|
1909
|
+
try {
|
|
1910
|
+
resolved = resolveBootstrapWorkspace(snapshot.repo_names || []);
|
|
1911
|
+
} catch (err) {
|
|
1912
|
+
console.error(err?.message || err);
|
|
1913
|
+
process.exit(1);
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
const wrapperRoot = resolved.root;
|
|
1917
|
+
const outputDir = args["output-dir"] || args.outputDir || args.output_dir;
|
|
1918
|
+
const dryRun = Boolean(args["dry-run"] || args.dryRun);
|
|
1919
|
+
const counts = snapshot.counts && typeof snapshot.counts === "object" ? snapshot.counts : {};
|
|
1920
|
+
const summary = {
|
|
1921
|
+
api_base: apiBase,
|
|
1922
|
+
project_id: snapshot?.project?.id || null,
|
|
1923
|
+
wrapper_root: wrapperRoot,
|
|
1924
|
+
output_root: outputDir ? path.resolve(process.cwd(), String(outputDir)) : path.join(wrapperRoot, "MyteCommandCenter"),
|
|
1925
|
+
repo_names: Array.isArray(snapshot.repo_names) ? snapshot.repo_names : [],
|
|
1926
|
+
local: {
|
|
1927
|
+
mode: resolved.mode,
|
|
1928
|
+
found: (resolved.repos || []).map((repo) => repo.name),
|
|
1929
|
+
missing: resolved.missing || [],
|
|
1930
|
+
},
|
|
1931
|
+
filters: snapshot.filters && typeof snapshot.filters === "object" ? snapshot.filters : filters,
|
|
1932
|
+
counts,
|
|
1933
|
+
snapshot_hash: snapshot.snapshot_hash || null,
|
|
1934
|
+
generated_at: snapshot.generated_at || null,
|
|
1935
|
+
dry_run: dryRun,
|
|
1936
|
+
};
|
|
1937
|
+
|
|
1938
|
+
if (dryRun) {
|
|
1939
|
+
if (args.json) {
|
|
1940
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
1941
|
+
} else {
|
|
1942
|
+
console.log(`Project: ${summary.project_id || "(unknown)"}`);
|
|
1943
|
+
console.log(`Wrapper root: ${summary.wrapper_root}`);
|
|
1944
|
+
console.log(`Output root: ${summary.output_root}`);
|
|
1945
|
+
console.log(`Configured repos: ${summary.repo_names.join(", ") || "(none)"}`);
|
|
1946
|
+
console.log(`Found locally: ${summary.local.found.join(", ") || "(none)"}`);
|
|
1947
|
+
if (summary.local.missing.length) console.log(`Missing locally: ${summary.local.missing.join(", ")}`);
|
|
1948
|
+
console.log(`Counts: total_feedback=${summary.counts.total_feedback || 0}, with_prd_text=${summary.counts.with_prd_text || 0}`);
|
|
1949
|
+
console.log("Dry run only - no files written.");
|
|
1950
|
+
}
|
|
1951
|
+
return;
|
|
1952
|
+
}
|
|
1953
|
+
|
|
1954
|
+
const writeResult = writeFeedbackSnapshot({ snapshot, wrapperRoot, outputDir });
|
|
1955
|
+
summary.data_root = writeResult.dataRoot;
|
|
1956
|
+
|
|
1957
|
+
if (args.json) {
|
|
1958
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
1959
|
+
return;
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
console.log(`Project: ${summary.project_id || "(unknown)"}`);
|
|
1963
|
+
console.log(`Wrapper root: ${summary.wrapper_root}`);
|
|
1964
|
+
console.log(`Output root: ${summary.output_root}`);
|
|
1965
|
+
console.log(`Configured repos: ${summary.repo_names.join(", ") || "(none)"}`);
|
|
1966
|
+
console.log(`Found locally: ${summary.local.found.join(", ") || "(none)"}`);
|
|
1967
|
+
if (summary.local.missing.length) console.log(`Missing locally: ${summary.local.missing.join(", ")}`);
|
|
1968
|
+
console.log(`Wrote feedback: total_feedback=${summary.counts.total_feedback || 0}, with_prd_text=${summary.counts.with_prd_text || 0}`);
|
|
1969
|
+
console.log(`Snapshot: ${summary.snapshot_hash || "n/a"}`);
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1350
1972
|
async function runQuery(args) {
|
|
1351
1973
|
const key = (process.env.MYTE_API_KEY || process.env.MYTE_PROJECT_API_KEY || "").trim();
|
|
1352
1974
|
if (!key) {
|
|
@@ -1490,6 +2112,11 @@ async function main() {
|
|
|
1490
2112
|
return;
|
|
1491
2113
|
}
|
|
1492
2114
|
|
|
2115
|
+
if (command === "feedback-sync") {
|
|
2116
|
+
await runFeedbackSync(args);
|
|
2117
|
+
return;
|
|
2118
|
+
}
|
|
2119
|
+
|
|
1493
2120
|
if (command === "chat") {
|
|
1494
2121
|
await runChat(args);
|
|
1495
2122
|
return;
|
|
@@ -1500,6 +2127,21 @@ async function main() {
|
|
|
1500
2127
|
return;
|
|
1501
2128
|
}
|
|
1502
2129
|
|
|
2130
|
+
if (command === "update-team") {
|
|
2131
|
+
await runUpdateTeam(args);
|
|
2132
|
+
return;
|
|
2133
|
+
}
|
|
2134
|
+
|
|
2135
|
+
if (command === "update-owner") {
|
|
2136
|
+
await runUpdateOwner(args);
|
|
2137
|
+
return;
|
|
2138
|
+
}
|
|
2139
|
+
|
|
2140
|
+
if (command === "update-client") {
|
|
2141
|
+
await runUpdateClient(args);
|
|
2142
|
+
return;
|
|
2143
|
+
}
|
|
2144
|
+
|
|
1503
2145
|
// query/ask default
|
|
1504
2146
|
await runQuery(args);
|
|
1505
2147
|
}
|