@mytegroupinc/myte-core 0.0.22 → 0.0.23
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 +3 -1
- package/cli.js +779 -33
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,6 +19,8 @@ This package exists so the public wrapper can stay small and versioned cleanly.
|
|
|
19
19
|
## Behavior Summary
|
|
20
20
|
|
|
21
21
|
- Snapshot-style commands such as `bootstrap`, `sync-qaqc`, `feedback-sync`, and `suggestions sync` write local `MyteCommandCenter` data.
|
|
22
|
-
- `feedback status|edit|assign|archive` writes reviewable local YAML artifacts
|
|
22
|
+
- `feedback status|edit|assign|archive` writes reviewable local YAML artifacts; `feedback submit|revise|reviews|review` routes them through the backend owner-review membrane.
|
|
23
|
+
- `feedback move|undo|prd-versions|prd-diff|history` calls the project-key Feedback API while leaving lifecycle rules and permissions server-side.
|
|
24
|
+
- `feedback validate|apply` remains available for validation and owner-direct apply paths; live authorization, stale checks, and history stay server-side.
|
|
23
25
|
- `query --with-diff` requires project repos to be configured for diff collection and fails fast when no matching local project repo can be resolved.
|
|
24
26
|
- Public package documentation is intentionally minimal. Internal rollout and design notes are not part of the npm package contract.
|
package/cli.js
CHANGED
|
@@ -144,6 +144,14 @@ function parseArgs(argv) {
|
|
|
144
144
|
"status",
|
|
145
145
|
"source",
|
|
146
146
|
"feedback-id",
|
|
147
|
+
"request-id",
|
|
148
|
+
"event-id",
|
|
149
|
+
"version-id",
|
|
150
|
+
"compare-to",
|
|
151
|
+
"action",
|
|
152
|
+
"decision",
|
|
153
|
+
"to-state",
|
|
154
|
+
"from-state",
|
|
147
155
|
"reason",
|
|
148
156
|
"review-action",
|
|
149
157
|
"idempotency-key",
|
|
@@ -152,6 +160,7 @@ function parseArgs(argv) {
|
|
|
152
160
|
"due-date",
|
|
153
161
|
"priority",
|
|
154
162
|
"review-note",
|
|
163
|
+
"final-file",
|
|
155
164
|
"tags",
|
|
156
165
|
"tag",
|
|
157
166
|
"mission-ids",
|
|
@@ -227,6 +236,14 @@ function printHelp() {
|
|
|
227
236
|
" myte feedback-sync [--status <value>] [--source <value>] [--with-prd-text|--no-with-prd-text] [--output-dir ./MyteCommandCenter] [--json]",
|
|
228
237
|
" myte feedback status --feedback-id <id> --status todo|in_progress|in_review|completed|deployed|rejected|archived --reason \"...\"",
|
|
229
238
|
" myte feedback edit --feedback-id <id> [--title \"...\"] [--feedback-text \"...\"] [--priority High] [--reason \"...\"]",
|
|
239
|
+
" myte feedback submit --file ./MyteCommandCenter/reviews/feedback/<id>-edit.yml [--json]",
|
|
240
|
+
" myte feedback revise --request-id <id> --file ./MyteCommandCenter/reviews/feedback/<id>-edit.yml [--json]",
|
|
241
|
+
" myte feedback reviews [--status open|terminal|all] [--request-id <id>] [--json]",
|
|
242
|
+
" myte feedback review --request-id <id> --action approve|reject|request_changes|cancel [--reason \"...\"] [--json]",
|
|
243
|
+
" myte feedback move --feedback-id <id> --to-state in_progress --from-state todo --reason \"...\" [--json]",
|
|
244
|
+
" myte feedback undo --feedback-id <id> --event-id <id> --reason \"...\" [--json]",
|
|
245
|
+
" myte feedback prd-versions --feedback-id <id> [--json]",
|
|
246
|
+
" myte feedback prd-diff --feedback-id <id> --version-id <id> [--compare-to <id>] [--json]",
|
|
230
247
|
" myte feedback validate --file ./MyteCommandCenter/reviews/feedback/<id>-status.yml [--json]",
|
|
231
248
|
" myte feedback apply --file ./MyteCommandCenter/reviews/feedback/<id>-status.yml [--json]",
|
|
232
249
|
" myte create-prd <file.md> [more.md ...] [--json] [--title \"...\"] [--description \"...\"]",
|
|
@@ -309,7 +326,11 @@ function printHelp() {
|
|
|
309
326
|
"",
|
|
310
327
|
"feedback review contract:",
|
|
311
328
|
" - Draft commands write review artifacts under MyteCommandCenter/reviews/feedback/*.yml for local IDE diff review",
|
|
312
|
-
" -
|
|
329
|
+
" - submit/revise route artifacts through the owner-review membrane before live feedback mutation",
|
|
330
|
+
" - reviews/review expose owner/delegate approval, rejection, request-changes, and cancel decisions",
|
|
331
|
+
" - move/undo operate safe board states directly; governed states remain backend-authorized",
|
|
332
|
+
" - prd-versions/prd-diff expose retained PRD versions and backend-generated text diffs",
|
|
333
|
+
" - validate/apply send artifacts to /api/project-assistant/feedback/<id>/refinement/* for validation or owner-direct apply",
|
|
313
334
|
" - The backend owns authorization, stale snapshot checks, allowed field/transition rules, and history",
|
|
314
335
|
" - apply is idempotent and does not rewrite local feedback.yml; run feedback-sync after apply to refresh local state",
|
|
315
336
|
"",
|
|
@@ -334,6 +355,13 @@ function printHelp() {
|
|
|
334
355
|
" --target-contact-id Add one client contact ObjectId (repeatable)",
|
|
335
356
|
" --target-contact-ids Comma-separated client contact ObjectIds",
|
|
336
357
|
" --feedback-id <id> Feedback ObjectId for feedback review commands",
|
|
358
|
+
" --request-id <id> Feedback review request ObjectId for submit/revise/review flows",
|
|
359
|
+
" --event-id <id> Feedback board event ObjectId for undo",
|
|
360
|
+
" --version-id <id> Feedback PRD version ObjectId for prd-diff",
|
|
361
|
+
" --compare-to <id> Optional base PRD version ObjectId for prd-diff",
|
|
362
|
+
" --action <value> Feedback review action: approve, reject, request_changes, or cancel",
|
|
363
|
+
" --to-state <value> Target canonical feedback board state for feedback move",
|
|
364
|
+
" --from-state <value> Optional current-state guard for feedback move",
|
|
337
365
|
" --reason <text> Human review reason included in feedback refinement artifacts",
|
|
338
366
|
" --status <value> Mission status target, feedback-sync filter, or feedback review state depending on command",
|
|
339
367
|
" --source <value> Feedback source filter for feedback-sync",
|
|
@@ -371,6 +399,10 @@ function printHelp() {
|
|
|
371
399
|
" myte update-client --subject \"Weekly client update\" --body-file ./updates/week-12.md",
|
|
372
400
|
" myte feedback-sync --json",
|
|
373
401
|
" myte feedback status --feedback-id 507f1f77bcf86cd799439011 --status in_review --reason \"Ready for owner review\"",
|
|
402
|
+
" myte feedback submit --file ./MyteCommandCenter/reviews/feedback/507f1f77bcf86cd799439011-edit.yml --json",
|
|
403
|
+
" myte feedback reviews --status open --json",
|
|
404
|
+
" myte feedback review --request-id 507f1f77bcf86cd799439022 --action approve --reason \"Looks correct\" --json",
|
|
405
|
+
" myte feedback move --feedback-id 507f1f77bcf86cd799439011 --to-state in_progress --reason \"Started\" --json",
|
|
374
406
|
" myte feedback validate --file ./MyteCommandCenter/reviews/feedback/507f1f77bcf86cd799439011-status.yml --json",
|
|
375
407
|
" myte feedback apply --file ./MyteCommandCenter/reviews/feedback/507f1f77bcf86cd799439011-status.yml --json",
|
|
376
408
|
" myte suggestions create --file ./suggestions/create.yml",
|
|
@@ -1711,6 +1743,208 @@ async function postFeedbackRefinement({ apiBase, key, timeoutMs, feedbackId, mod
|
|
|
1711
1743
|
return body.data || {};
|
|
1712
1744
|
}
|
|
1713
1745
|
|
|
1746
|
+
async function fetchFeedbackReviewRequests({ apiBase, key, timeoutMs, status, limit, offset }) {
|
|
1747
|
+
const fetchFn = await getFetch();
|
|
1748
|
+
const url = new URL(`${apiBase}/project-assistant/feedback-review-requests`);
|
|
1749
|
+
if (status) url.searchParams.set("status", String(status));
|
|
1750
|
+
if (limit !== undefined && limit !== null && String(limit).trim()) url.searchParams.set("limit", String(limit));
|
|
1751
|
+
if (offset !== undefined && offset !== null && String(offset).trim()) url.searchParams.set("offset", String(offset));
|
|
1752
|
+
const { resp, body } = await fetchJsonWithTimeout(
|
|
1753
|
+
fetchFn,
|
|
1754
|
+
url.toString(),
|
|
1755
|
+
{
|
|
1756
|
+
method: "GET",
|
|
1757
|
+
headers: { Authorization: `Bearer ${key}` },
|
|
1758
|
+
},
|
|
1759
|
+
timeoutMs
|
|
1760
|
+
);
|
|
1761
|
+
|
|
1762
|
+
if (!resp.ok || body.status !== "success") {
|
|
1763
|
+
const msg = body?.message || `Feedback review requests failed (${resp.status})`;
|
|
1764
|
+
const err = new Error(msg);
|
|
1765
|
+
err.status = resp.status;
|
|
1766
|
+
throw err;
|
|
1767
|
+
}
|
|
1768
|
+
return body.data || {};
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
async function fetchFeedbackReviewRequest({ apiBase, key, timeoutMs, requestId }) {
|
|
1772
|
+
const fetchFn = await getFetch();
|
|
1773
|
+
const url = `${apiBase}/project-assistant/feedback-review-requests/${encodeURIComponent(String(requestId || ""))}`;
|
|
1774
|
+
const { resp, body } = await fetchJsonWithTimeout(
|
|
1775
|
+
fetchFn,
|
|
1776
|
+
url,
|
|
1777
|
+
{
|
|
1778
|
+
method: "GET",
|
|
1779
|
+
headers: { Authorization: `Bearer ${key}` },
|
|
1780
|
+
},
|
|
1781
|
+
timeoutMs
|
|
1782
|
+
);
|
|
1783
|
+
|
|
1784
|
+
if (!resp.ok || body.status !== "success") {
|
|
1785
|
+
const msg = body?.message || `Feedback review request failed (${resp.status})`;
|
|
1786
|
+
const err = new Error(msg);
|
|
1787
|
+
err.status = resp.status;
|
|
1788
|
+
throw err;
|
|
1789
|
+
}
|
|
1790
|
+
return body.data || {};
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
async function fetchFeedbackEvents({ apiBase, key, timeoutMs, feedbackId, limit }) {
|
|
1794
|
+
const fetchFn = await getFetch();
|
|
1795
|
+
const url = new URL(`${apiBase}/project-assistant/feedback/${encodeURIComponent(String(feedbackId || ""))}/events`);
|
|
1796
|
+
if (limit !== undefined && limit !== null && String(limit).trim()) url.searchParams.set("limit", String(limit));
|
|
1797
|
+
const { resp, body } = await fetchJsonWithTimeout(
|
|
1798
|
+
fetchFn,
|
|
1799
|
+
url.toString(),
|
|
1800
|
+
{
|
|
1801
|
+
method: "GET",
|
|
1802
|
+
headers: { Authorization: `Bearer ${key}` },
|
|
1803
|
+
},
|
|
1804
|
+
timeoutMs
|
|
1805
|
+
);
|
|
1806
|
+
|
|
1807
|
+
if (!resp.ok || body.status !== "success") {
|
|
1808
|
+
const msg = body?.message || `Feedback events request failed (${resp.status})`;
|
|
1809
|
+
const err = new Error(msg);
|
|
1810
|
+
err.status = resp.status;
|
|
1811
|
+
throw err;
|
|
1812
|
+
}
|
|
1813
|
+
return body.data || {};
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
async function postFeedbackReviewSubmission({ apiBase, key, timeoutMs, feedbackId, payload, idempotencyKey, clientSessionId }) {
|
|
1817
|
+
const fetchFn = await getFetch();
|
|
1818
|
+
const url = `${apiBase}/project-assistant/feedback/${encodeURIComponent(String(feedbackId || ""))}/refinement/requests`;
|
|
1819
|
+
const { resp, body } = await fetchJsonWithTimeout(
|
|
1820
|
+
fetchFn,
|
|
1821
|
+
url,
|
|
1822
|
+
{
|
|
1823
|
+
method: "POST",
|
|
1824
|
+
headers: {
|
|
1825
|
+
"Content-Type": "application/json",
|
|
1826
|
+
Authorization: `Bearer ${key}`,
|
|
1827
|
+
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
1828
|
+
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
1829
|
+
},
|
|
1830
|
+
body: JSON.stringify(payload || {}),
|
|
1831
|
+
},
|
|
1832
|
+
timeoutMs
|
|
1833
|
+
);
|
|
1834
|
+
|
|
1835
|
+
if (!resp.ok || body.status !== "success") {
|
|
1836
|
+
const msg = body?.message || `Feedback review submission failed (${resp.status})`;
|
|
1837
|
+
const err = new Error(msg);
|
|
1838
|
+
err.status = resp.status;
|
|
1839
|
+
err.data = body?.data;
|
|
1840
|
+
throw err;
|
|
1841
|
+
}
|
|
1842
|
+
return body.data || {};
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1845
|
+
async function postFeedbackReviewRequestMutation({ apiBase, key, timeoutMs, requestId, endpointAction, payload, idempotencyKey, clientSessionId }) {
|
|
1846
|
+
const fetchFn = await getFetch();
|
|
1847
|
+
const url = `${apiBase}/project-assistant/feedback-review-requests/${encodeURIComponent(String(requestId || ""))}/${endpointAction}`;
|
|
1848
|
+
const { resp, body } = await fetchJsonWithTimeout(
|
|
1849
|
+
fetchFn,
|
|
1850
|
+
url,
|
|
1851
|
+
{
|
|
1852
|
+
method: "POST",
|
|
1853
|
+
headers: {
|
|
1854
|
+
"Content-Type": "application/json",
|
|
1855
|
+
Authorization: `Bearer ${key}`,
|
|
1856
|
+
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
1857
|
+
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
1858
|
+
},
|
|
1859
|
+
body: JSON.stringify(payload || {}),
|
|
1860
|
+
},
|
|
1861
|
+
timeoutMs
|
|
1862
|
+
);
|
|
1863
|
+
|
|
1864
|
+
if (!resp.ok || body.status !== "success") {
|
|
1865
|
+
const msg = body?.message || `Feedback review ${endpointAction} failed (${resp.status})`;
|
|
1866
|
+
const err = new Error(msg);
|
|
1867
|
+
err.status = resp.status;
|
|
1868
|
+
err.data = body?.data;
|
|
1869
|
+
throw err;
|
|
1870
|
+
}
|
|
1871
|
+
return body.data || {};
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1874
|
+
async function postFeedbackBoardMutation({ apiBase, key, timeoutMs, feedbackId, endpoint, payload, idempotencyKey, clientSessionId }) {
|
|
1875
|
+
const fetchFn = await getFetch();
|
|
1876
|
+
const url = `${apiBase}/project-assistant/feedback/${encodeURIComponent(String(feedbackId || ""))}/${endpoint}`;
|
|
1877
|
+
const { resp, body } = await fetchJsonWithTimeout(
|
|
1878
|
+
fetchFn,
|
|
1879
|
+
url,
|
|
1880
|
+
{
|
|
1881
|
+
method: "POST",
|
|
1882
|
+
headers: {
|
|
1883
|
+
"Content-Type": "application/json",
|
|
1884
|
+
Authorization: `Bearer ${key}`,
|
|
1885
|
+
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
1886
|
+
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
1887
|
+
},
|
|
1888
|
+
body: JSON.stringify(payload || {}),
|
|
1889
|
+
},
|
|
1890
|
+
timeoutMs
|
|
1891
|
+
);
|
|
1892
|
+
|
|
1893
|
+
if (!resp.ok || body.status !== "success") {
|
|
1894
|
+
const msg = body?.message || `Feedback board mutation failed (${resp.status})`;
|
|
1895
|
+
const err = new Error(msg);
|
|
1896
|
+
err.status = resp.status;
|
|
1897
|
+
err.data = body?.data;
|
|
1898
|
+
throw err;
|
|
1899
|
+
}
|
|
1900
|
+
return body.data || {};
|
|
1901
|
+
}
|
|
1902
|
+
|
|
1903
|
+
async function fetchFeedbackPrdVersions({ apiBase, key, timeoutMs, feedbackId }) {
|
|
1904
|
+
const fetchFn = await getFetch();
|
|
1905
|
+
const url = `${apiBase}/project-assistant/feedback/${encodeURIComponent(String(feedbackId || ""))}/prd/versions`;
|
|
1906
|
+
const { resp, body } = await fetchJsonWithTimeout(
|
|
1907
|
+
fetchFn,
|
|
1908
|
+
url,
|
|
1909
|
+
{
|
|
1910
|
+
method: "GET",
|
|
1911
|
+
headers: { Authorization: `Bearer ${key}` },
|
|
1912
|
+
},
|
|
1913
|
+
timeoutMs
|
|
1914
|
+
);
|
|
1915
|
+
|
|
1916
|
+
if (!resp.ok || body.status !== "success") {
|
|
1917
|
+
const msg = body?.message || `Feedback PRD versions request failed (${resp.status})`;
|
|
1918
|
+
const err = new Error(msg);
|
|
1919
|
+
err.status = resp.status;
|
|
1920
|
+
throw err;
|
|
1921
|
+
}
|
|
1922
|
+
return body.data || {};
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
async function fetchFeedbackPrdVersionDiff({ apiBase, key, timeoutMs, feedbackId, versionId, compareTo }) {
|
|
1926
|
+
const fetchFn = await getFetch();
|
|
1927
|
+
const url = new URL(`${apiBase}/project-assistant/feedback/${encodeURIComponent(String(feedbackId || ""))}/prd/versions/${encodeURIComponent(String(versionId || ""))}/diff`);
|
|
1928
|
+
if (compareTo) url.searchParams.set("compare_to", String(compareTo));
|
|
1929
|
+
const { resp, body } = await fetchJsonWithTimeout(
|
|
1930
|
+
fetchFn,
|
|
1931
|
+
url.toString(),
|
|
1932
|
+
{
|
|
1933
|
+
method: "GET",
|
|
1934
|
+
headers: { Authorization: `Bearer ${key}` },
|
|
1935
|
+
},
|
|
1936
|
+
timeoutMs
|
|
1937
|
+
);
|
|
1938
|
+
|
|
1939
|
+
if (!resp.ok || body.status !== "success") {
|
|
1940
|
+
const msg = body?.message || `Feedback PRD version diff failed (${resp.status})`;
|
|
1941
|
+
const err = new Error(msg);
|
|
1942
|
+
err.status = resp.status;
|
|
1943
|
+
throw err;
|
|
1944
|
+
}
|
|
1945
|
+
return body.data || {};
|
|
1946
|
+
}
|
|
1947
|
+
|
|
1714
1948
|
async function fetchSuggestionsSyncSnapshot({ apiBase, key, timeoutMs, actorScope = "" }) {
|
|
1715
1949
|
const fetchFn = await getFetch();
|
|
1716
1950
|
const url = new URL(`${apiBase}/project-assistant/suggestions`);
|
|
@@ -4268,7 +4502,7 @@ async function buildFeedbackDraftForCommand(args, subcommand) {
|
|
|
4268
4502
|
const reviewNote = firstNonEmptyString(args["review-note"], args.reviewNote, args.review_note);
|
|
4269
4503
|
if (reviewNote) changes.review_note = feedbackChange(null, reviewNote);
|
|
4270
4504
|
} else {
|
|
4271
|
-
console.error("Unknown feedback command. Use status, edit, assign, archive,
|
|
4505
|
+
console.error("Unknown feedback draft command. Use status, edit, assign, archive, or refine.");
|
|
4272
4506
|
process.exit(1);
|
|
4273
4507
|
}
|
|
4274
4508
|
|
|
@@ -4382,69 +4616,581 @@ async function runFeedbackValidateOrApply(args, mode) {
|
|
|
4382
4616
|
}
|
|
4383
4617
|
}
|
|
4384
4618
|
|
|
4385
|
-
|
|
4619
|
+
function resolveFeedbackRequestIdArg(args) {
|
|
4620
|
+
return firstNonEmptyString(args["request-id"], args.requestId, args.request_id, args._?.[1]);
|
|
4621
|
+
}
|
|
4622
|
+
|
|
4623
|
+
function resolveFeedbackEventIdArg(args) {
|
|
4624
|
+
return firstNonEmptyString(args["event-id"], args.eventId, args.event_id, args._?.[1]);
|
|
4625
|
+
}
|
|
4626
|
+
|
|
4627
|
+
function resolveFeedbackVersionIdArg(args) {
|
|
4628
|
+
return firstNonEmptyString(args["version-id"], args.versionId, args.version_id, args._?.[1]);
|
|
4629
|
+
}
|
|
4630
|
+
|
|
4631
|
+
function summarizeFeedbackReviewRequestPayload(data) {
|
|
4632
|
+
const request = data?.request || data || {};
|
|
4633
|
+
return {
|
|
4634
|
+
request_id: request.request_id || request._id || null,
|
|
4635
|
+
feedback_id: request.feedback_id || request.feedback?.feedback_id || null,
|
|
4636
|
+
status: request.status || null,
|
|
4637
|
+
title: request.title || request.feedback?.title || null,
|
|
4638
|
+
can_review: request.can_review === true,
|
|
4639
|
+
can_approve: request.can_approve === true,
|
|
4640
|
+
is_terminal: request.is_terminal === true,
|
|
4641
|
+
stale: request.stale === true,
|
|
4642
|
+
conflicted: request.conflicted === true,
|
|
4643
|
+
warnings: Array.isArray(request.warnings) ? request.warnings : [],
|
|
4644
|
+
};
|
|
4645
|
+
}
|
|
4646
|
+
|
|
4647
|
+
function printFeedbackReviewRequestSummary(data, args) {
|
|
4648
|
+
const summary = summarizeFeedbackReviewRequestPayload(data);
|
|
4649
|
+
if (args.json) {
|
|
4650
|
+
console.log(JSON.stringify(data, null, 2));
|
|
4651
|
+
return;
|
|
4652
|
+
}
|
|
4653
|
+
console.log(`Request: ${summary.request_id || "(unknown)"}`);
|
|
4654
|
+
console.log(`Feedback: ${summary.feedback_id || "(unknown)"}`);
|
|
4655
|
+
console.log(`Status: ${summary.status || "unknown"}`);
|
|
4656
|
+
if (summary.title) console.log(`Title: ${summary.title}`);
|
|
4657
|
+
console.log(`Can approve: ${summary.can_approve ? "yes" : "no"}`);
|
|
4658
|
+
if (summary.stale || summary.conflicted) {
|
|
4659
|
+
console.log(`Conflict: stale=${summary.stale ? "yes" : "no"}, conflicted=${summary.conflicted ? "yes" : "no"}`);
|
|
4660
|
+
}
|
|
4661
|
+
}
|
|
4662
|
+
|
|
4663
|
+
async function runFeedbackSubmit(args) {
|
|
4386
4664
|
const key = getProjectApiKey();
|
|
4387
4665
|
if (!key) {
|
|
4388
4666
|
console.error("Missing MYTE_API_KEY (project key) in environment/.env");
|
|
4389
4667
|
process.exit(1);
|
|
4390
4668
|
}
|
|
4391
|
-
const
|
|
4669
|
+
const { absPath, payload } = readFeedbackRefinementArtifact(args);
|
|
4670
|
+
const feedbackId = firstNonEmptyString(args["feedback-id"], args.feedbackId, args.feedback_id, payload.feedback_id);
|
|
4392
4671
|
if (!feedbackId) {
|
|
4393
|
-
console.error("
|
|
4672
|
+
console.error("Feedback refinement artifact is missing feedback_id.");
|
|
4394
4673
|
process.exit(1);
|
|
4395
4674
|
}
|
|
4396
4675
|
const timeoutMs = resolveTimeoutMs(args);
|
|
4397
4676
|
const apiBase = resolveApiBase(args);
|
|
4677
|
+
const clientSessionId = firstNonEmptyString(
|
|
4678
|
+
args["client-session-id"],
|
|
4679
|
+
args.clientSessionId,
|
|
4680
|
+
args.client_session_id,
|
|
4681
|
+
payload.client_session_id
|
|
4682
|
+
);
|
|
4683
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
4684
|
+
args,
|
|
4685
|
+
operation: `feedback_refinement_request_submit:${feedbackId}`,
|
|
4686
|
+
payload,
|
|
4687
|
+
});
|
|
4398
4688
|
|
|
4399
4689
|
let data;
|
|
4400
4690
|
try {
|
|
4401
|
-
data =
|
|
4402
|
-
|
|
4403
|
-
|
|
4691
|
+
data = await postFeedbackReviewSubmission({
|
|
4692
|
+
apiBase,
|
|
4693
|
+
key,
|
|
4694
|
+
timeoutMs,
|
|
4695
|
+
feedbackId,
|
|
4696
|
+
payload,
|
|
4697
|
+
idempotencyKey,
|
|
4698
|
+
clientSessionId,
|
|
4699
|
+
});
|
|
4404
4700
|
} catch (err) {
|
|
4405
|
-
|
|
4701
|
+
if (args.json) {
|
|
4702
|
+
console.log(JSON.stringify({ ok: false, status: err?.status || null, message: err?.message || String(err), data: err?.data || null, artifact_path: absPath }, null, 2));
|
|
4703
|
+
} else {
|
|
4704
|
+
console.error("Feedback submit failed:", err?.message || err);
|
|
4705
|
+
if (err?.data) console.error(JSON.stringify(err.data, null, 2));
|
|
4706
|
+
}
|
|
4406
4707
|
process.exit(1);
|
|
4407
4708
|
}
|
|
4408
4709
|
|
|
4710
|
+
const output = {
|
|
4711
|
+
ok: true,
|
|
4712
|
+
artifact_path: absPath,
|
|
4713
|
+
feedback_id: data.feedback_id || feedbackId,
|
|
4714
|
+
project_id: data.project_id || null,
|
|
4715
|
+
pending_review_count: data.pending_review_count || null,
|
|
4716
|
+
request: data.request || null,
|
|
4717
|
+
permissions: data.permissions || null,
|
|
4718
|
+
};
|
|
4409
4719
|
if (args.json) {
|
|
4410
|
-
console.log(JSON.stringify(
|
|
4411
|
-
return;
|
|
4412
|
-
}
|
|
4413
|
-
if (mode === "history") {
|
|
4414
|
-
console.log(`Feedback: ${data.feedback_id || feedbackId}`);
|
|
4415
|
-
console.log(`Events: ${data.count || 0}`);
|
|
4416
|
-
for (const event of data.events || []) {
|
|
4417
|
-
console.log(`- ${event.created_at || "unknown"} ${event.action || "refine"} ${event.history_id || ""}`);
|
|
4418
|
-
}
|
|
4720
|
+
console.log(JSON.stringify(output, null, 2));
|
|
4419
4721
|
return;
|
|
4420
4722
|
}
|
|
4421
|
-
|
|
4422
|
-
console.log(`
|
|
4423
|
-
console.log(`
|
|
4424
|
-
console.log(
|
|
4425
|
-
console.log(`Priority: ${feedback.priority || "n/a"}`);
|
|
4426
|
-
console.log(`Snapshot: ${feedback.snapshot_hash || "n/a"}`);
|
|
4723
|
+
console.log(`Feedback: ${output.feedback_id}`);
|
|
4724
|
+
console.log(`Review request: ${output.request?.request_id || output.request?._id || "(unknown)"}`);
|
|
4725
|
+
console.log(`Status: ${output.request?.status || "pending_review"}`);
|
|
4726
|
+
console.log("Live feedback was not mutated. Owner/delegate approval is required.");
|
|
4427
4727
|
}
|
|
4428
4728
|
|
|
4429
|
-
async function
|
|
4430
|
-
const
|
|
4431
|
-
if (
|
|
4432
|
-
|
|
4433
|
-
|
|
4729
|
+
async function runFeedbackRevise(args) {
|
|
4730
|
+
const key = getProjectApiKey();
|
|
4731
|
+
if (!key) {
|
|
4732
|
+
console.error("Missing MYTE_API_KEY (project key) in environment/.env");
|
|
4733
|
+
process.exit(1);
|
|
4434
4734
|
}
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4735
|
+
const requestId = resolveFeedbackRequestIdArg(args);
|
|
4736
|
+
if (!requestId) {
|
|
4737
|
+
console.error("Missing --request-id.");
|
|
4738
|
+
process.exit(1);
|
|
4739
|
+
}
|
|
4740
|
+
const { absPath, payload } = readFeedbackRefinementArtifact(args);
|
|
4741
|
+
const timeoutMs = resolveTimeoutMs(args);
|
|
4742
|
+
const apiBase = resolveApiBase(args);
|
|
4743
|
+
const clientSessionId = firstNonEmptyString(
|
|
4744
|
+
args["client-session-id"],
|
|
4745
|
+
args.clientSessionId,
|
|
4746
|
+
args.client_session_id,
|
|
4747
|
+
payload.client_session_id
|
|
4748
|
+
);
|
|
4749
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
4750
|
+
args,
|
|
4751
|
+
operation: `feedback_refinement_request_revise:${requestId}`,
|
|
4752
|
+
payload,
|
|
4753
|
+
});
|
|
4754
|
+
|
|
4755
|
+
let data;
|
|
4756
|
+
try {
|
|
4757
|
+
data = await postFeedbackReviewRequestMutation({
|
|
4758
|
+
apiBase,
|
|
4759
|
+
key,
|
|
4760
|
+
timeoutMs,
|
|
4761
|
+
requestId,
|
|
4762
|
+
endpointAction: "revise",
|
|
4763
|
+
payload,
|
|
4764
|
+
idempotencyKey,
|
|
4765
|
+
clientSessionId,
|
|
4766
|
+
});
|
|
4767
|
+
} catch (err) {
|
|
4768
|
+
if (args.json) {
|
|
4769
|
+
console.log(JSON.stringify({ ok: false, status: err?.status || null, message: err?.message || String(err), data: err?.data || null, artifact_path: absPath }, null, 2));
|
|
4770
|
+
} else {
|
|
4771
|
+
console.error("Feedback revise failed:", err?.message || err);
|
|
4772
|
+
if (err?.data) console.error(JSON.stringify(err.data, null, 2));
|
|
4773
|
+
}
|
|
4774
|
+
process.exit(1);
|
|
4775
|
+
}
|
|
4776
|
+
|
|
4777
|
+
const output = { ok: true, artifact_path: absPath, ...data };
|
|
4778
|
+
if (args.json) {
|
|
4779
|
+
console.log(JSON.stringify(output, null, 2));
|
|
4780
|
+
return;
|
|
4781
|
+
}
|
|
4782
|
+
printFeedbackReviewRequestSummary(data, args);
|
|
4783
|
+
}
|
|
4784
|
+
|
|
4785
|
+
async function runFeedbackReviews(args) {
|
|
4786
|
+
const key = getProjectApiKey();
|
|
4787
|
+
if (!key) {
|
|
4788
|
+
console.error("Missing MYTE_API_KEY (project key) in environment/.env");
|
|
4789
|
+
process.exit(1);
|
|
4790
|
+
}
|
|
4791
|
+
const timeoutMs = resolveTimeoutMs(args);
|
|
4792
|
+
const apiBase = resolveApiBase(args);
|
|
4793
|
+
const requestId = firstNonEmptyString(args["request-id"], args.requestId, args.request_id);
|
|
4794
|
+
|
|
4795
|
+
let data;
|
|
4796
|
+
try {
|
|
4797
|
+
data = requestId
|
|
4798
|
+
? await fetchFeedbackReviewRequest({ apiBase, key, timeoutMs, requestId })
|
|
4799
|
+
: await fetchFeedbackReviewRequests({
|
|
4800
|
+
apiBase,
|
|
4801
|
+
key,
|
|
4802
|
+
timeoutMs,
|
|
4803
|
+
status: firstNonEmptyString(args.status) || "open",
|
|
4804
|
+
limit: firstNonEmptyString(args.limit) || undefined,
|
|
4805
|
+
offset: firstNonEmptyString(args.offset) || undefined,
|
|
4806
|
+
});
|
|
4807
|
+
} catch (err) {
|
|
4808
|
+
console.error("Feedback reviews failed:", err?.message || err);
|
|
4809
|
+
process.exit(1);
|
|
4810
|
+
}
|
|
4811
|
+
|
|
4812
|
+
if (args.json) {
|
|
4813
|
+
console.log(JSON.stringify(data, null, 2));
|
|
4814
|
+
return;
|
|
4815
|
+
}
|
|
4816
|
+
if (requestId) {
|
|
4817
|
+
printFeedbackReviewRequestSummary(data, args);
|
|
4818
|
+
return;
|
|
4819
|
+
}
|
|
4820
|
+
const requests = Array.isArray(data.requests) ? data.requests : [];
|
|
4821
|
+
console.log(`Review requests: ${requests.length}/${data.total ?? requests.length}`);
|
|
4822
|
+
for (const requestItem of requests) {
|
|
4823
|
+
const summary = summarizeFeedbackReviewRequestPayload(requestItem);
|
|
4824
|
+
console.log(`- ${summary.request_id || "(unknown)"} ${summary.status || "unknown"} feedback=${summary.feedback_id || "(unknown)"} title=${summary.title || "(untitled)"}`);
|
|
4825
|
+
}
|
|
4826
|
+
}
|
|
4827
|
+
|
|
4828
|
+
function buildFeedbackReviewDecisionPayload(args, action) {
|
|
4829
|
+
const filePath = firstNonEmptyString(args.file);
|
|
4830
|
+
let payload = {};
|
|
4831
|
+
if (filePath) {
|
|
4832
|
+
const fromFile = readStructuredPayloadFile(filePath, "Feedback review");
|
|
4833
|
+
payload = Array.isArray(fromFile?.items) ? fromFile.items[0] || {} : fromFile;
|
|
4834
|
+
}
|
|
4835
|
+
if (!isPlainObject(payload)) {
|
|
4836
|
+
throw new Error("Feedback review payload must be an object.");
|
|
4837
|
+
}
|
|
4838
|
+
const nextPayload = { ...payload };
|
|
4839
|
+
const reason = firstNonEmptyString(args.reason, args["review-note"], args.reviewNote, args.review_note);
|
|
4840
|
+
if (reason && !nextPayload.reason && !nextPayload.review_reason) {
|
|
4841
|
+
nextPayload.reason = reason;
|
|
4842
|
+
}
|
|
4843
|
+
const finalFile = firstNonEmptyString(args["final-file"], args.finalFile, args.final_file);
|
|
4844
|
+
if (finalFile) {
|
|
4845
|
+
nextPayload.final_change_set = readStructuredPayloadFile(finalFile, "Feedback final change set");
|
|
4846
|
+
}
|
|
4847
|
+
if (action === "approve" || action === "reject") {
|
|
4848
|
+
nextPayload.decision = action;
|
|
4849
|
+
}
|
|
4850
|
+
return nextPayload;
|
|
4851
|
+
}
|
|
4852
|
+
|
|
4853
|
+
async function runFeedbackReviewDecision(args) {
|
|
4854
|
+
const key = getProjectApiKey();
|
|
4855
|
+
if (!key) {
|
|
4856
|
+
console.error("Missing MYTE_API_KEY (project key) in environment/.env");
|
|
4857
|
+
process.exit(1);
|
|
4858
|
+
}
|
|
4859
|
+
const requestId = resolveFeedbackRequestIdArg(args);
|
|
4860
|
+
if (!requestId) {
|
|
4861
|
+
console.error("Missing --request-id.");
|
|
4862
|
+
process.exit(1);
|
|
4863
|
+
}
|
|
4864
|
+
const action = String(firstNonEmptyString(args.action, args.decision, args["review-action"], args.reviewAction, args.review_action, args._?.[1]) || "").trim().toLowerCase().replace(/-/g, "_");
|
|
4865
|
+
if (!["approve", "reject", "request_changes", "cancel"].includes(action)) {
|
|
4866
|
+
console.error("Missing or invalid review action. Use approve, reject, request_changes, or cancel.");
|
|
4867
|
+
process.exit(1);
|
|
4868
|
+
}
|
|
4869
|
+
|
|
4870
|
+
let payload;
|
|
4871
|
+
try {
|
|
4872
|
+
payload = buildFeedbackReviewDecisionPayload(args, action);
|
|
4873
|
+
} catch (err) {
|
|
4874
|
+
console.error(err?.message || err);
|
|
4875
|
+
process.exit(1);
|
|
4876
|
+
}
|
|
4877
|
+
const endpointAction = action === "request_changes" ? "request-changes" : action === "cancel" ? "cancel" : "review";
|
|
4878
|
+
const timeoutMs = resolveTimeoutMs(args);
|
|
4879
|
+
const apiBase = resolveApiBase(args);
|
|
4880
|
+
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id, payload.client_session_id);
|
|
4881
|
+
const operationAction = action === "request_changes" ? "request_changes" : action;
|
|
4882
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
4883
|
+
args,
|
|
4884
|
+
operation: `feedback_review_request_${operationAction}:${requestId}`,
|
|
4885
|
+
payload,
|
|
4886
|
+
});
|
|
4887
|
+
|
|
4888
|
+
let data;
|
|
4889
|
+
try {
|
|
4890
|
+
data = await postFeedbackReviewRequestMutation({
|
|
4891
|
+
apiBase,
|
|
4892
|
+
key,
|
|
4893
|
+
timeoutMs,
|
|
4894
|
+
requestId,
|
|
4895
|
+
endpointAction,
|
|
4896
|
+
payload,
|
|
4897
|
+
idempotencyKey,
|
|
4898
|
+
clientSessionId,
|
|
4899
|
+
});
|
|
4900
|
+
} catch (err) {
|
|
4901
|
+
if (args.json) {
|
|
4902
|
+
console.log(JSON.stringify({ ok: false, status: err?.status || null, message: err?.message || String(err), data: err?.data || null }, null, 2));
|
|
4903
|
+
} else {
|
|
4904
|
+
console.error(`Feedback review ${action} failed:`, err?.message || err);
|
|
4905
|
+
if (err?.data) console.error(JSON.stringify(err.data, null, 2));
|
|
4906
|
+
}
|
|
4907
|
+
process.exit(1);
|
|
4908
|
+
}
|
|
4909
|
+
|
|
4910
|
+
if (args.json) {
|
|
4911
|
+
console.log(JSON.stringify({ ok: true, action, ...data }, null, 2));
|
|
4912
|
+
return;
|
|
4913
|
+
}
|
|
4914
|
+
printFeedbackReviewRequestSummary(data, args);
|
|
4915
|
+
}
|
|
4916
|
+
|
|
4917
|
+
async function runFeedbackMove(args) {
|
|
4918
|
+
const key = getProjectApiKey();
|
|
4919
|
+
if (!key) {
|
|
4920
|
+
console.error("Missing MYTE_API_KEY (project key) in environment/.env");
|
|
4921
|
+
process.exit(1);
|
|
4922
|
+
}
|
|
4923
|
+
const feedbackId = resolveFeedbackIdArg(args);
|
|
4924
|
+
if (!feedbackId) {
|
|
4925
|
+
console.error("Missing --feedback-id.");
|
|
4926
|
+
process.exit(1);
|
|
4927
|
+
}
|
|
4928
|
+
const toState = firstNonEmptyString(args["to-state"], args.toState, args.to_state, args.status, args._?.[1]);
|
|
4929
|
+
if (!toState) {
|
|
4930
|
+
console.error("Missing --to-state for feedback move.");
|
|
4931
|
+
process.exit(1);
|
|
4932
|
+
}
|
|
4933
|
+
const payload = {
|
|
4934
|
+
to_state: toState,
|
|
4935
|
+
from_state: firstNonEmptyString(args["from-state"], args.fromState, args.from_state) || undefined,
|
|
4936
|
+
reason: firstNonEmptyString(args.reason) || undefined,
|
|
4937
|
+
};
|
|
4938
|
+
const timeoutMs = resolveTimeoutMs(args);
|
|
4939
|
+
const apiBase = resolveApiBase(args);
|
|
4940
|
+
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id);
|
|
4941
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
4942
|
+
args,
|
|
4943
|
+
operation: `feedback_board_move:${feedbackId}`,
|
|
4944
|
+
payload,
|
|
4945
|
+
});
|
|
4946
|
+
|
|
4947
|
+
let data;
|
|
4948
|
+
try {
|
|
4949
|
+
data = await postFeedbackBoardMutation({
|
|
4950
|
+
apiBase,
|
|
4951
|
+
key,
|
|
4952
|
+
timeoutMs,
|
|
4953
|
+
feedbackId,
|
|
4954
|
+
endpoint: "board-move",
|
|
4955
|
+
payload,
|
|
4956
|
+
idempotencyKey,
|
|
4957
|
+
clientSessionId,
|
|
4958
|
+
});
|
|
4959
|
+
} catch (err) {
|
|
4960
|
+
if (args.json) {
|
|
4961
|
+
console.log(JSON.stringify({ ok: false, status: err?.status || null, message: err?.message || String(err), data: err?.data || null }, null, 2));
|
|
4962
|
+
} else {
|
|
4963
|
+
console.error("Feedback move failed:", err?.message || err);
|
|
4964
|
+
if (err?.data) console.error(JSON.stringify(err.data, null, 2));
|
|
4965
|
+
}
|
|
4966
|
+
process.exit(1);
|
|
4967
|
+
}
|
|
4968
|
+
|
|
4969
|
+
if (args.json) {
|
|
4970
|
+
console.log(JSON.stringify({ ok: true, ...data }, null, 2));
|
|
4971
|
+
return;
|
|
4972
|
+
}
|
|
4973
|
+
console.log(`Feedback: ${data.feedback_id || feedbackId}`);
|
|
4974
|
+
console.log(`State: ${data.feedback_state || toState}`);
|
|
4975
|
+
if (data.event?.event_id) console.log(`Event: ${data.event.event_id}`);
|
|
4976
|
+
}
|
|
4977
|
+
|
|
4978
|
+
async function runFeedbackUndo(args) {
|
|
4979
|
+
const key = getProjectApiKey();
|
|
4980
|
+
if (!key) {
|
|
4981
|
+
console.error("Missing MYTE_API_KEY (project key) in environment/.env");
|
|
4982
|
+
process.exit(1);
|
|
4983
|
+
}
|
|
4984
|
+
const feedbackId = resolveFeedbackIdArg(args);
|
|
4985
|
+
const eventId = resolveFeedbackEventIdArg(args);
|
|
4986
|
+
if (!feedbackId) {
|
|
4987
|
+
console.error("Missing --feedback-id.");
|
|
4988
|
+
process.exit(1);
|
|
4989
|
+
}
|
|
4990
|
+
if (!eventId) {
|
|
4991
|
+
console.error("Missing --event-id.");
|
|
4992
|
+
process.exit(1);
|
|
4993
|
+
}
|
|
4994
|
+
const payload = { reason: firstNonEmptyString(args.reason) || undefined };
|
|
4995
|
+
const timeoutMs = resolveTimeoutMs(args);
|
|
4996
|
+
const apiBase = resolveApiBase(args);
|
|
4997
|
+
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id);
|
|
4998
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
4999
|
+
args,
|
|
5000
|
+
operation: `feedback_event_undo:${feedbackId}:${eventId}`,
|
|
5001
|
+
payload,
|
|
5002
|
+
});
|
|
5003
|
+
|
|
5004
|
+
let data;
|
|
5005
|
+
try {
|
|
5006
|
+
data = await postFeedbackBoardMutation({
|
|
5007
|
+
apiBase,
|
|
5008
|
+
key,
|
|
5009
|
+
timeoutMs,
|
|
5010
|
+
feedbackId,
|
|
5011
|
+
endpoint: `events/${encodeURIComponent(String(eventId))}/undo`,
|
|
5012
|
+
payload,
|
|
5013
|
+
idempotencyKey,
|
|
5014
|
+
clientSessionId,
|
|
5015
|
+
});
|
|
5016
|
+
} catch (err) {
|
|
5017
|
+
if (args.json) {
|
|
5018
|
+
console.log(JSON.stringify({ ok: false, status: err?.status || null, message: err?.message || String(err), data: err?.data || null }, null, 2));
|
|
5019
|
+
} else {
|
|
5020
|
+
console.error("Feedback undo failed:", err?.message || err);
|
|
5021
|
+
if (err?.data) console.error(JSON.stringify(err.data, null, 2));
|
|
5022
|
+
}
|
|
5023
|
+
process.exit(1);
|
|
5024
|
+
}
|
|
5025
|
+
|
|
5026
|
+
if (args.json) {
|
|
5027
|
+
console.log(JSON.stringify({ ok: true, ...data }, null, 2));
|
|
5028
|
+
return;
|
|
5029
|
+
}
|
|
5030
|
+
console.log(`Feedback: ${data.feedback_id || feedbackId}`);
|
|
5031
|
+
console.log(`State: ${data.feedback_state || "unknown"}`);
|
|
5032
|
+
if (data.reverted_event_id) console.log(`Reverted: ${data.reverted_event_id}`);
|
|
5033
|
+
}
|
|
5034
|
+
|
|
5035
|
+
async function runFeedbackPrdVersions(args) {
|
|
5036
|
+
const key = getProjectApiKey();
|
|
5037
|
+
if (!key) {
|
|
5038
|
+
console.error("Missing MYTE_API_KEY (project key) in environment/.env");
|
|
5039
|
+
process.exit(1);
|
|
5040
|
+
}
|
|
5041
|
+
const feedbackId = resolveFeedbackIdArg(args);
|
|
5042
|
+
if (!feedbackId) {
|
|
5043
|
+
console.error("Missing --feedback-id.");
|
|
5044
|
+
process.exit(1);
|
|
5045
|
+
}
|
|
5046
|
+
const timeoutMs = resolveTimeoutMs(args);
|
|
5047
|
+
const apiBase = resolveApiBase(args);
|
|
5048
|
+
let data;
|
|
5049
|
+
try {
|
|
5050
|
+
data = await fetchFeedbackPrdVersions({ apiBase, key, timeoutMs, feedbackId });
|
|
5051
|
+
} catch (err) {
|
|
5052
|
+
console.error("Feedback PRD versions failed:", err?.message || err);
|
|
5053
|
+
process.exit(1);
|
|
5054
|
+
}
|
|
5055
|
+
if (args.json) {
|
|
5056
|
+
console.log(JSON.stringify(data, null, 2));
|
|
5057
|
+
return;
|
|
5058
|
+
}
|
|
5059
|
+
const versions = Array.isArray(data.versions) ? data.versions : [];
|
|
5060
|
+
console.log(`PRD versions: ${versions.length}`);
|
|
5061
|
+
for (const version of versions) {
|
|
5062
|
+
console.log(`- ${version.version_id || version._id || "(unknown)"} v${version.version_number || "?"} active=${String(version._id || version.version_id) === String(data.active_prd_version_id) ? "yes" : "no"}`);
|
|
5063
|
+
}
|
|
5064
|
+
}
|
|
5065
|
+
|
|
5066
|
+
async function runFeedbackPrdDiff(args) {
|
|
5067
|
+
const key = getProjectApiKey();
|
|
5068
|
+
if (!key) {
|
|
5069
|
+
console.error("Missing MYTE_API_KEY (project key) in environment/.env");
|
|
5070
|
+
process.exit(1);
|
|
5071
|
+
}
|
|
5072
|
+
const feedbackId = resolveFeedbackIdArg(args);
|
|
5073
|
+
const versionId = resolveFeedbackVersionIdArg(args);
|
|
5074
|
+
if (!feedbackId) {
|
|
5075
|
+
console.error("Missing --feedback-id.");
|
|
5076
|
+
process.exit(1);
|
|
5077
|
+
}
|
|
5078
|
+
if (!versionId) {
|
|
5079
|
+
console.error("Missing --version-id.");
|
|
5080
|
+
process.exit(1);
|
|
5081
|
+
}
|
|
5082
|
+
const timeoutMs = resolveTimeoutMs(args);
|
|
5083
|
+
const apiBase = resolveApiBase(args);
|
|
5084
|
+
const compareTo = firstNonEmptyString(args["compare-to"], args.compareTo, args.compare_to);
|
|
5085
|
+
let data;
|
|
5086
|
+
try {
|
|
5087
|
+
data = await fetchFeedbackPrdVersionDiff({ apiBase, key, timeoutMs, feedbackId, versionId, compareTo });
|
|
5088
|
+
} catch (err) {
|
|
5089
|
+
console.error("Feedback PRD diff failed:", err?.message || err);
|
|
5090
|
+
process.exit(1);
|
|
5091
|
+
}
|
|
5092
|
+
if (args.json) {
|
|
5093
|
+
console.log(JSON.stringify(data, null, 2));
|
|
5094
|
+
return;
|
|
5095
|
+
}
|
|
5096
|
+
console.log(data.diff || "");
|
|
5097
|
+
}
|
|
5098
|
+
|
|
5099
|
+
async function runFeedbackGetOrHistory(args, mode) {
|
|
5100
|
+
const key = getProjectApiKey();
|
|
5101
|
+
if (!key) {
|
|
5102
|
+
console.error("Missing MYTE_API_KEY (project key) in environment/.env");
|
|
5103
|
+
process.exit(1);
|
|
5104
|
+
}
|
|
5105
|
+
const feedbackId = resolveFeedbackIdArg(args);
|
|
5106
|
+
if (!feedbackId) {
|
|
5107
|
+
console.error("Missing --feedback-id.");
|
|
5108
|
+
process.exit(1);
|
|
5109
|
+
}
|
|
5110
|
+
const timeoutMs = resolveTimeoutMs(args);
|
|
5111
|
+
const apiBase = resolveApiBase(args);
|
|
5112
|
+
|
|
5113
|
+
let data;
|
|
5114
|
+
try {
|
|
5115
|
+
data = mode === "history"
|
|
5116
|
+
? await fetchFeedbackEvents({ apiBase, key, timeoutMs, feedbackId, limit: firstNonEmptyString(args.limit) || undefined })
|
|
5117
|
+
: await fetchFeedbackReview({ apiBase, key, timeoutMs, feedbackId });
|
|
5118
|
+
} catch (err) {
|
|
5119
|
+
console.error(`Feedback ${mode} failed:`, err?.message || err);
|
|
5120
|
+
process.exit(1);
|
|
5121
|
+
}
|
|
5122
|
+
|
|
5123
|
+
if (args.json) {
|
|
5124
|
+
console.log(JSON.stringify(data, null, 2));
|
|
5125
|
+
return;
|
|
5126
|
+
}
|
|
5127
|
+
if (mode === "history") {
|
|
5128
|
+
console.log(`Feedback: ${data.feedback_id || feedbackId}`);
|
|
5129
|
+
console.log(`Events: ${data.count || 0}`);
|
|
5130
|
+
for (const event of data.events || []) {
|
|
5131
|
+
console.log(`- ${event.created_at || "unknown"} ${event.action || "refine"} ${event.history_id || ""}`);
|
|
5132
|
+
}
|
|
5133
|
+
return;
|
|
5134
|
+
}
|
|
5135
|
+
const feedback = data.feedback || {};
|
|
5136
|
+
console.log(`Feedback: ${feedback.feedback_id || feedbackId}`);
|
|
5137
|
+
console.log(`Title: ${feedback.title || "(untitled)"}`);
|
|
5138
|
+
console.log(`Status: ${feedback.feedback_state || feedback.status || "unknown"} (${feedback.status || "legacy unknown"})`);
|
|
5139
|
+
console.log(`Priority: ${feedback.priority || "n/a"}`);
|
|
5140
|
+
console.log(`Snapshot: ${feedback.snapshot_hash || "n/a"}`);
|
|
5141
|
+
}
|
|
5142
|
+
|
|
5143
|
+
async function runFeedback(args) {
|
|
5144
|
+
const subcommand = firstNonEmptyString(args._?.[0]) || "help";
|
|
5145
|
+
if (subcommand === "help") {
|
|
5146
|
+
printHelp();
|
|
5147
|
+
return;
|
|
5148
|
+
}
|
|
5149
|
+
if (["status", "edit", "assign", "archive", "refine"].includes(subcommand)) {
|
|
5150
|
+
await buildFeedbackDraftForCommand(args, subcommand);
|
|
5151
|
+
return;
|
|
4438
5152
|
}
|
|
4439
5153
|
if (subcommand === "validate" || subcommand === "apply") {
|
|
4440
5154
|
await runFeedbackValidateOrApply(args, subcommand);
|
|
4441
5155
|
return;
|
|
4442
5156
|
}
|
|
5157
|
+
if (subcommand === "submit") {
|
|
5158
|
+
await runFeedbackSubmit(args);
|
|
5159
|
+
return;
|
|
5160
|
+
}
|
|
5161
|
+
if (subcommand === "revise") {
|
|
5162
|
+
await runFeedbackRevise(args);
|
|
5163
|
+
return;
|
|
5164
|
+
}
|
|
5165
|
+
if (subcommand === "reviews" || subcommand === "requests") {
|
|
5166
|
+
await runFeedbackReviews(args);
|
|
5167
|
+
return;
|
|
5168
|
+
}
|
|
5169
|
+
if (subcommand === "review") {
|
|
5170
|
+
await runFeedbackReviewDecision(args);
|
|
5171
|
+
return;
|
|
5172
|
+
}
|
|
5173
|
+
if (subcommand === "move") {
|
|
5174
|
+
await runFeedbackMove(args);
|
|
5175
|
+
return;
|
|
5176
|
+
}
|
|
5177
|
+
if (subcommand === "undo") {
|
|
5178
|
+
await runFeedbackUndo(args);
|
|
5179
|
+
return;
|
|
5180
|
+
}
|
|
5181
|
+
if (subcommand === "prd-versions") {
|
|
5182
|
+
await runFeedbackPrdVersions(args);
|
|
5183
|
+
return;
|
|
5184
|
+
}
|
|
5185
|
+
if (subcommand === "prd-diff") {
|
|
5186
|
+
await runFeedbackPrdDiff(args);
|
|
5187
|
+
return;
|
|
5188
|
+
}
|
|
4443
5189
|
if (subcommand === "get" || subcommand === "history") {
|
|
4444
5190
|
await runFeedbackGetOrHistory(args, subcommand);
|
|
4445
5191
|
return;
|
|
4446
5192
|
}
|
|
4447
|
-
console.error("Unknown feedback command. Use status, edit, assign, archive, get, history, validate, or apply.");
|
|
5193
|
+
console.error("Unknown feedback command. Use status, edit, assign, archive, submit, revise, reviews, review, move, undo, prd-versions, prd-diff, get, history, validate, or apply.");
|
|
4448
5194
|
process.exit(1);
|
|
4449
5195
|
}
|
|
4450
5196
|
|