@mytegroupinc/myte-core 0.0.44 → 0.0.45
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 +65 -65
- package/THIRD_PARTY_NOTICES.md +21 -21
- package/TRADEMARKS.md +10 -10
- package/cli.js +904 -876
- package/lib/mytecody-release-public-key.pem +11 -11
- package/lib/mytecody-splash.js +251 -251
- package/mytecody-cli.js +2025 -2025
- package/package.json +14 -14
package/cli.js
CHANGED
|
@@ -208,10 +208,10 @@ function printHelp() {
|
|
|
208
208
|
" myte feedback reviews [--status open|terminal|all] [--request-id <id>] [--json]",
|
|
209
209
|
" myte feedback review --request-id <id> --action approve|reject|request_changes|cancel [--reason \"...\"] [--json]",
|
|
210
210
|
" myte feedback review --request-ids \"<id1,id2>\" --action approve|reject|request_changes|cancel [--reason \"...\"] [--json]",
|
|
211
|
-
" myte feedback move --feedback-id <id> --to-state in_progress --from-state todo --reason \"...\" [--json]",
|
|
212
|
-
" myte feedback move --feedback-ids \"<id1,id2>\" --to-state in_progress --reason \"...\" [--json]",
|
|
213
|
-
" myte feedback comment --feedback-id <id> --body \"...\" [--body-file ./comment.md] [--json]",
|
|
214
|
-
" myte feedback undo --feedback-id <id> --event-id <id> --reason \"...\" [--json]",
|
|
211
|
+
" myte feedback move --feedback-id <id> --to-state in_progress --from-state todo --reason \"...\" [--json]",
|
|
212
|
+
" myte feedback move --feedback-ids \"<id1,id2>\" --to-state in_progress --reason \"...\" [--json]",
|
|
213
|
+
" myte feedback comment --feedback-id <id> --body \"...\" [--body-file ./comment.md] [--json]",
|
|
214
|
+
" myte feedback undo --feedback-id <id> --event-id <id> --reason \"...\" [--json]",
|
|
215
215
|
" myte feedback prd-versions --feedback-id <id> [--json]",
|
|
216
216
|
" myte feedback prd-diff --feedback-id <id> --version-id <id> [--compare-to <id>] [--json]",
|
|
217
217
|
" myte feedback validate --file ./MyteCommandCenter/reviews/feedback/<id>-status.yml [--json]",
|
|
@@ -231,16 +231,16 @@ function printHelp() {
|
|
|
231
231
|
" npx myte@latest query \"What changed in logging?\" --with-diff",
|
|
232
232
|
" npx myte@latest ai \"Return a JSON checklist\" --json-response",
|
|
233
233
|
"",
|
|
234
|
-
"Auth:",
|
|
235
|
-
" - Set MYTE_API_KEY in a workspace .env (or env var)",
|
|
236
|
-
" - Set MYTEAI_API_KEY in a workspace .env (or env var) for `myte ai`",
|
|
237
|
-
"",
|
|
238
|
-
"Live write approval:",
|
|
239
|
-
" - Live project-key mutations require --confirm-write --approval-artifact <path>",
|
|
240
|
-
" - The artifact must be a local .md, .yml/.yaml, or .json file shown to and approved by the user before the command is rerun",
|
|
241
|
-
" - Batch artifacts must enumerate every feedback id, mission id, suggestion id, request id, or PRD item",
|
|
242
|
-
" - Read/sync/query/validate, --print-context, and --dry-run commands do not require write approval",
|
|
243
|
-
"",
|
|
234
|
+
"Auth:",
|
|
235
|
+
" - Set MYTE_API_KEY in a workspace .env (or env var)",
|
|
236
|
+
" - Set MYTEAI_API_KEY in a workspace .env (or env var) for `myte ai`",
|
|
237
|
+
"",
|
|
238
|
+
"Live write approval:",
|
|
239
|
+
" - Live project-key mutations require --confirm-write --approval-artifact <path>",
|
|
240
|
+
" - The artifact must be a local .md, .yml/.yaml, or .json file shown to and approved by the user before the command is rerun",
|
|
241
|
+
" - Batch artifacts must enumerate every feedback id, mission id, suggestion id, request id, or PRD item",
|
|
242
|
+
" - Read/sync/query/validate, --print-context, and --dry-run commands do not require write approval",
|
|
243
|
+
"",
|
|
244
244
|
"bootstrap contract:",
|
|
245
245
|
" - Run from any workspace where you want local MyteCommandCenter data written",
|
|
246
246
|
" - Writes MyteCommandCenter/data/project.yml plus phases, epics, stories, and missions locally",
|
|
@@ -319,7 +319,7 @@ function printHelp() {
|
|
|
319
319
|
" - Archived feedback is intentionally excluded from normal sync; returning it to active work is web UI only",
|
|
320
320
|
" - Writes project feedback metadata and conversation turns into MyteCommandCenter/data/feedback.yml",
|
|
321
321
|
" - Stores full PRD context in MyteCommandCenter/PRD/feedback-sync/*.md and points to those files from feedback.yml",
|
|
322
|
-
" - Reads existing feedback comments and can create text-only feedback-specific comments through the project-key API",
|
|
322
|
+
" - Reads existing feedback comments and can create text-only feedback-specific comments through the project-key API",
|
|
323
323
|
"",
|
|
324
324
|
"feedback review contract:",
|
|
325
325
|
" - Draft commands write review artifacts under MyteCommandCenter/reviews/feedback/*.yml for local IDE diff review",
|
|
@@ -328,9 +328,9 @@ function printHelp() {
|
|
|
328
328
|
" - reviews/review expose owner/delegate approval, rejection, request-changes, and cancel decisions",
|
|
329
329
|
" - review with --request-ids sends one batch review request; it does not loop single-review calls",
|
|
330
330
|
" - live lifecycle moves return pending_feedback_review while an active linked review request exists",
|
|
331
|
-
" - move/undo operate safe board states directly; governed states remain backend-authorized",
|
|
332
|
-
" - move with --feedback-ids sends one batch board move request; it supports active-state moves and authorized archive",
|
|
333
|
-
" - comment creates text-only feedback-specific comments; attachments remain web UI only for this endpoint",
|
|
331
|
+
" - move/undo operate safe board states directly; governed states remain backend-authorized",
|
|
332
|
+
" - move with --feedback-ids sends one batch board move request; it supports active-state moves and authorized archive",
|
|
333
|
+
" - comment creates text-only feedback-specific comments; attachments remain web UI only for this endpoint",
|
|
334
334
|
" - project-key API/CLI cannot unarchive archived Feedback; use the web archived Feedback view",
|
|
335
335
|
" - get/history read current feedback snapshots and audited event history through the project-key API",
|
|
336
336
|
" - prd-versions/prd-diff expose retained PRD versions and backend-generated text diffs",
|
|
@@ -346,9 +346,9 @@ function printHelp() {
|
|
|
346
346
|
" - revise: resubmit the original submitter's request after request_changes",
|
|
347
347
|
" - reviews: list open/terminal/all requests or inspect one request",
|
|
348
348
|
" - review: approve, reject, request_changes, or cancel; backend restricts this to owner/delegate capability",
|
|
349
|
-
" - move: direct audited board movement for allowed states; governed transitions remain backend-authorized",
|
|
350
|
-
" - comment: create a text-only comment on one Feedback item",
|
|
351
|
-
" - undo: reverse an audited board event when conflict checks allow it",
|
|
349
|
+
" - move: direct audited board movement for allowed states; governed transitions remain backend-authorized",
|
|
350
|
+
" - comment: create a text-only comment on one Feedback item",
|
|
351
|
+
" - undo: reverse an audited board event when conflict checks allow it",
|
|
352
352
|
" - prd-versions: list retained PRD baselines/revisions for a feedback item",
|
|
353
353
|
" - prd-diff: fetch backend-generated text diff between PRD versions",
|
|
354
354
|
" - history: list board/refinement events for audit review",
|
|
@@ -369,11 +369,11 @@ function printHelp() {
|
|
|
369
369
|
" --stdin Read supported command content from stdin instead of inline text or a file path",
|
|
370
370
|
" --title <text> Override PRD title for raw markdown uploads",
|
|
371
371
|
" --description <text> Set feedback description/card summary for raw markdown uploads",
|
|
372
|
-
" --content <text> Team update content for update-team",
|
|
373
|
-
" --body <text> Feedback comment body for feedback comment",
|
|
374
|
-
" --subject <text> Subject for update-owner or update-client",
|
|
372
|
+
" --content <text> Team update content for update-team",
|
|
373
|
+
" --body <text> Feedback comment body for feedback comment",
|
|
374
|
+
" --subject <text> Subject for update-owner or update-client",
|
|
375
375
|
" --body-markdown <md> Markdown body for update-owner or update-client",
|
|
376
|
-
" --body-file <path> Read feedback comment, update-owner, or update-client markdown body from a file",
|
|
376
|
+
" --body-file <path> Read feedback comment, update-owner, or update-client markdown body from a file",
|
|
377
377
|
" --target-contact-id Add one client contact ObjectId (repeatable)",
|
|
378
378
|
" --target-contact-ids Comma-separated client contact ObjectIds",
|
|
379
379
|
" --feedback-id <id> Feedback ObjectId for feedback review commands",
|
|
@@ -401,10 +401,10 @@ function printHelp() {
|
|
|
401
401
|
" --actor-scope <id> Actor workspace key inside mission-ops.yml (defaults to machine-cwd slug)",
|
|
402
402
|
" --wait Poll batch status until terminal completion for run-qaqc",
|
|
403
403
|
" --sync After run-qaqc completes, refresh local QAQC file",
|
|
404
|
-
" --force Allow run-qaqc to bypass stale-state protection when supported",
|
|
405
|
-
" --confirm-write Confirm the user explicitly approved a live Myte project-key mutation",
|
|
406
|
-
" --approval-artifact Local .md/.yml/.json approval artifact shown to and approved by the user",
|
|
407
|
-
" --no-sync Skip automatic post-mutation sync for suggestions, missions, and feedback mutations",
|
|
404
|
+
" --force Allow run-qaqc to bypass stale-state protection when supported",
|
|
405
|
+
" --confirm-write Confirm the user explicitly approved a live Myte project-key mutation",
|
|
406
|
+
" --approval-artifact Local .md/.yml/.json approval artifact shown to and approved by the user",
|
|
407
|
+
" --no-sync Skip automatic post-mutation sync for suggestions, missions, and feedback mutations",
|
|
408
408
|
" --print-context Print JSON payload and exit (no query call)",
|
|
409
409
|
" --no-fetch Don't git fetch origin main/master before diff",
|
|
410
410
|
"",
|
|
@@ -429,10 +429,10 @@ function printHelp() {
|
|
|
429
429
|
" myte feedback status --feedback-id 507f1f77bcf86cd799439011 --status in_review --reason \"Ready for owner review\"",
|
|
430
430
|
" myte feedback submit --file ./MyteCommandCenter/reviews/feedback/507f1f77bcf86cd799439011-edit.yml --json",
|
|
431
431
|
" myte feedback reviews --status open --json",
|
|
432
|
-
" myte feedback review --request-id 507f1f77bcf86cd799439022 --action approve --reason \"Looks correct\" --json",
|
|
433
|
-
" myte feedback move --feedback-id 507f1f77bcf86cd799439011 --to-state in_progress --reason \"Started\" --json",
|
|
434
|
-
" myte feedback comment --feedback-id 507f1f77bcf86cd799439011 --body \"Implementation notes are ready for review.\" --json",
|
|
435
|
-
" myte feedback validate --file ./MyteCommandCenter/reviews/feedback/507f1f77bcf86cd799439011-status.yml --json",
|
|
432
|
+
" myte feedback review --request-id 507f1f77bcf86cd799439022 --action approve --reason \"Looks correct\" --json",
|
|
433
|
+
" myte feedback move --feedback-id 507f1f77bcf86cd799439011 --to-state in_progress --reason \"Started\" --json",
|
|
434
|
+
" myte feedback comment --feedback-id 507f1f77bcf86cd799439011 --body \"Implementation notes are ready for review.\" --json",
|
|
435
|
+
" myte feedback validate --file ./MyteCommandCenter/reviews/feedback/507f1f77bcf86cd799439011-status.yml --json",
|
|
436
436
|
" myte feedback apply --file ./MyteCommandCenter/reviews/feedback/507f1f77bcf86cd799439011-status.yml --json",
|
|
437
437
|
" myte suggestions create --file ./suggestions/create.yml",
|
|
438
438
|
" myte suggestions revise",
|
|
@@ -678,10 +678,10 @@ function normalizeApiBase(baseRaw) {
|
|
|
678
678
|
return base.endsWith("/api") ? base : `${base}/api`;
|
|
679
679
|
}
|
|
680
680
|
|
|
681
|
-
async function fetchJsonWithTimeout(fetchFn, url, options, timeoutMs) {
|
|
682
|
-
const controller = typeof AbortController !== "undefined" ? new AbortController() : undefined;
|
|
683
|
-
const timeoutId =
|
|
684
|
-
controller && timeoutMs > 0 ? setTimeout(() => controller.abort(), timeoutMs) : undefined;
|
|
681
|
+
async function fetchJsonWithTimeout(fetchFn, url, options, timeoutMs) {
|
|
682
|
+
const controller = typeof AbortController !== "undefined" ? new AbortController() : undefined;
|
|
683
|
+
const timeoutId =
|
|
684
|
+
controller && timeoutMs > 0 ? setTimeout(() => controller.abort(), timeoutMs) : undefined;
|
|
685
685
|
try {
|
|
686
686
|
const resp = await fetchFn(url, { ...options, signal: controller?.signal });
|
|
687
687
|
const text = await resp.text();
|
|
@@ -697,171 +697,171 @@ async function fetchJsonWithTimeout(fetchFn, url, options, timeoutMs) {
|
|
|
697
697
|
}
|
|
698
698
|
return { resp, body };
|
|
699
699
|
} finally {
|
|
700
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
701
|
-
}
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
const WRITE_APPROVAL_TRANSPORT_KEYS = new Set(["write_approval", "client_session_id"]);
|
|
705
|
-
|
|
706
|
-
function canonicalizeWritePayload(value) {
|
|
707
|
-
if (Array.isArray(value)) {
|
|
708
|
-
return value.map((item) => canonicalizeWritePayload(item));
|
|
709
|
-
}
|
|
710
|
-
if (value && typeof value === "object") {
|
|
711
|
-
return Object.fromEntries(
|
|
712
|
-
Object.keys(value)
|
|
713
|
-
.filter((key) => !WRITE_APPROVAL_TRANSPORT_KEYS.has(String(key)))
|
|
714
|
-
.sort()
|
|
715
|
-
.map((key) => [key, canonicalizeWritePayload(value[key])])
|
|
716
|
-
);
|
|
717
|
-
}
|
|
718
|
-
return value;
|
|
719
|
-
}
|
|
720
|
-
|
|
700
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
const WRITE_APPROVAL_TRANSPORT_KEYS = new Set(["write_approval", "client_session_id"]);
|
|
705
|
+
|
|
706
|
+
function canonicalizeWritePayload(value) {
|
|
707
|
+
if (Array.isArray(value)) {
|
|
708
|
+
return value.map((item) => canonicalizeWritePayload(item));
|
|
709
|
+
}
|
|
710
|
+
if (value && typeof value === "object") {
|
|
711
|
+
return Object.fromEntries(
|
|
712
|
+
Object.keys(value)
|
|
713
|
+
.filter((key) => !WRITE_APPROVAL_TRANSPORT_KEYS.has(String(key)))
|
|
714
|
+
.sort()
|
|
715
|
+
.map((key) => [key, canonicalizeWritePayload(value[key])])
|
|
716
|
+
);
|
|
717
|
+
}
|
|
718
|
+
return value;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
721
|
function projectApiWritePayloadHash(payload) {
|
|
722
722
|
return createHash("sha256")
|
|
723
|
-
.update(
|
|
723
|
+
.update(pythonJsonDumpsCompatible(canonicalizeWritePayload(payload || {})))
|
|
724
724
|
.digest("hex");
|
|
725
725
|
}
|
|
726
|
-
|
|
727
|
-
function isConfirmWrite(args) {
|
|
728
|
-
return Boolean(args["confirm-write"] || args.confirmWrite || args.confirm_write);
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
function resolveWriteApprovalArtifactPath(args) {
|
|
732
|
-
const explicit = firstNonEmptyString(args["approval-artifact"], args.approvalArtifact, args.approval_artifact);
|
|
733
|
-
if (!explicit) return "";
|
|
734
|
-
const resolved = path.resolve(process.cwd(), explicit);
|
|
735
|
-
if (!fs.existsSync(resolved) || !fs.statSync(resolved).isFile()) {
|
|
736
|
-
console.error(`Approval artifact not found: ${resolved}`);
|
|
737
|
-
process.exit(1);
|
|
738
|
-
}
|
|
739
|
-
return resolved;
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
function inferApprovalArtifactKind(filePath, fallbackKind) {
|
|
743
|
-
const ext = path.extname(String(filePath || "")).toLowerCase();
|
|
744
|
-
if (ext === ".md" || ext === ".markdown") return "markdown";
|
|
745
|
-
if (ext === ".yml" || ext === ".yaml") return "yaml";
|
|
746
|
-
if (ext === ".json") return "json";
|
|
747
|
-
return fallbackKind || "artifact";
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
function normalizeApprovalTargets(targets) {
|
|
751
|
-
return toStringArray(targets).map((item) => item.trim()).filter(Boolean);
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
function writePayloadItems(payload) {
|
|
755
|
-
if (Array.isArray(payload?.items)) return payload.items;
|
|
756
|
-
if (Array.isArray(payload)) return payload;
|
|
757
|
-
return payload && typeof payload === "object" ? [payload] : [];
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
function suggestionApprovalTargets(payload) {
|
|
761
|
-
return writePayloadItems(payload).map((item, index) => {
|
|
762
|
-
if (!item || typeof item !== "object") return `index:${index}`;
|
|
763
|
-
return firstNonEmptyString(
|
|
764
|
-
item.suggestion_id,
|
|
765
|
-
item.id,
|
|
766
|
-
item._id,
|
|
767
|
-
item.mission_id,
|
|
768
|
-
item.target_mission_id,
|
|
769
|
-
item.title ? `${item.change_type || "suggestion"}:${item.title}` : ""
|
|
770
|
-
) || `index:${index}`;
|
|
771
|
-
});
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
function prdApprovalTargets(payload) {
|
|
775
|
-
return writePayloadItems(payload).map((item, index) => {
|
|
776
|
-
if (!item || typeof item !== "object") return `index:${index}`;
|
|
777
|
-
return firstNonEmptyString(item.client_ref, item.title) || `index:${index}`;
|
|
778
|
-
});
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
function requireWriteApproval(args, payload, { operation, artifactKind, targets = [], batchCount = null } = {}) {
|
|
782
|
-
const payloadSha256 = projectApiWritePayloadHash(payload || {});
|
|
783
|
-
const targetValues = normalizeApprovalTargets(targets);
|
|
784
|
-
const expectedBatchCount = batchCount !== null && batchCount !== undefined
|
|
785
|
-
? Number(batchCount)
|
|
786
|
-
: targetValues.length > 1
|
|
787
|
-
? targetValues.length
|
|
788
|
-
: null;
|
|
789
|
-
|
|
790
|
-
if (!isConfirmWrite(args)) {
|
|
791
|
-
console.error("Refusing live Myte write without explicit human approval.");
|
|
792
|
-
console.error(`Operation: ${operation || "unknown"}`);
|
|
793
|
-
console.error(`Payload SHA256: ${payloadSha256}`);
|
|
794
|
-
if (targetValues.length) console.error(`Targets: ${targetValues.join(", ")}`);
|
|
795
|
-
if (expectedBatchCount !== null) console.error(`Batch count: ${expectedBatchCount}`);
|
|
796
|
-
console.error("Create a local .md/.yml/.json approval artifact that lists the exact operation, payload summary, and every target.");
|
|
797
|
-
console.error("Show that artifact to the user and ask for explicit approval.");
|
|
798
|
-
console.error("Then rerun with --confirm-write --approval-artifact <path>.");
|
|
799
|
-
process.exit(1);
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
const artifactPath = resolveWriteApprovalArtifactPath(args);
|
|
803
|
-
if (!artifactPath) {
|
|
804
|
-
console.error("Missing --approval-artifact <path> for approved Myte write.");
|
|
805
|
-
console.error(`Payload SHA256: ${payloadSha256}`);
|
|
806
|
-
console.error("The artifact must be a local .md/.yml/.json file shown to and explicitly approved by the user.");
|
|
807
|
-
process.exit(1);
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
return {
|
|
811
|
-
approved: true,
|
|
812
|
-
source: "explicit_user_approval",
|
|
813
|
-
artifact_path: artifactPath,
|
|
814
|
-
artifact_kind: inferApprovalArtifactKind(artifactPath, artifactKind),
|
|
815
|
-
payload_sha256: payloadSha256,
|
|
816
|
-
targets: targetValues,
|
|
817
|
-
batch_count: expectedBatchCount,
|
|
818
|
-
};
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
function writeApprovalHeaders(writeApproval) {
|
|
822
|
-
if (!writeApproval) return {};
|
|
823
|
-
const headers = {
|
|
824
|
-
"X-Myte-Write-Approval": "explicit_user_approval",
|
|
825
|
-
"X-Myte-Approval-Artifact": String(writeApproval.artifact_path || ""),
|
|
826
|
-
"X-Myte-Approval-Artifact-Kind": String(writeApproval.artifact_kind || ""),
|
|
827
|
-
"X-Myte-Approval-Payload-SHA256": String(writeApproval.payload_sha256 || ""),
|
|
828
|
-
};
|
|
829
|
-
if (writeApproval.batch_count !== null && writeApproval.batch_count !== undefined) {
|
|
830
|
-
headers["X-Myte-Approval-Batch-Count"] = String(writeApproval.batch_count);
|
|
831
|
-
}
|
|
832
|
-
if (Array.isArray(writeApproval.targets) && writeApproval.targets.length) {
|
|
833
|
-
headers["X-Myte-Approval-Targets"] = writeApproval.targets.join(",");
|
|
834
|
-
}
|
|
835
|
-
return headers;
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
function formatProjectApiErrorMessage(body, fallback) {
|
|
839
|
-
const message = body?.message || fallback;
|
|
840
|
-
const data = body?.data || {};
|
|
841
|
-
const code = String(data?.code || "");
|
|
842
|
-
if (!code.startsWith("myte_write_approval")) {
|
|
843
|
-
return message;
|
|
844
|
-
}
|
|
845
|
-
const lines = [
|
|
846
|
-
message,
|
|
847
|
-
`Approval error: ${code}`,
|
|
848
|
-
];
|
|
849
|
-
if (data.operation) lines.push(`Operation: ${data.operation}`);
|
|
850
|
-
if (data.payload_sha256) lines.push(`Payload SHA256: ${data.payload_sha256}`);
|
|
851
|
-
if (Array.isArray(data.targets) && data.targets.length) lines.push(`Targets: ${data.targets.join(", ")}`);
|
|
852
|
-
if (data.batch_count !== undefined && data.batch_count !== null) lines.push(`Batch count: ${data.batch_count}`);
|
|
853
|
-
if (Array.isArray(data.required_agent_steps) && data.required_agent_steps.length) {
|
|
854
|
-
lines.push("Required agent steps:");
|
|
855
|
-
for (const step of data.required_agent_steps) {
|
|
856
|
-
lines.push(`- ${step}`);
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
return lines.join("\n");
|
|
860
|
-
}
|
|
861
|
-
|
|
862
|
-
function summarizeDiffDiagnosticsForContext(diagnostics) {
|
|
863
|
-
if (!diagnostics) return null;
|
|
864
|
-
const repos = Array.isArray(diagnostics.repo_summaries)
|
|
726
|
+
|
|
727
|
+
function isConfirmWrite(args) {
|
|
728
|
+
return Boolean(args["confirm-write"] || args.confirmWrite || args.confirm_write);
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
function resolveWriteApprovalArtifactPath(args) {
|
|
732
|
+
const explicit = firstNonEmptyString(args["approval-artifact"], args.approvalArtifact, args.approval_artifact);
|
|
733
|
+
if (!explicit) return "";
|
|
734
|
+
const resolved = path.resolve(process.cwd(), explicit);
|
|
735
|
+
if (!fs.existsSync(resolved) || !fs.statSync(resolved).isFile()) {
|
|
736
|
+
console.error(`Approval artifact not found: ${resolved}`);
|
|
737
|
+
process.exit(1);
|
|
738
|
+
}
|
|
739
|
+
return resolved;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
function inferApprovalArtifactKind(filePath, fallbackKind) {
|
|
743
|
+
const ext = path.extname(String(filePath || "")).toLowerCase();
|
|
744
|
+
if (ext === ".md" || ext === ".markdown") return "markdown";
|
|
745
|
+
if (ext === ".yml" || ext === ".yaml") return "yaml";
|
|
746
|
+
if (ext === ".json") return "json";
|
|
747
|
+
return fallbackKind || "artifact";
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
function normalizeApprovalTargets(targets) {
|
|
751
|
+
return toStringArray(targets).map((item) => item.trim()).filter(Boolean);
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
function writePayloadItems(payload) {
|
|
755
|
+
if (Array.isArray(payload?.items)) return payload.items;
|
|
756
|
+
if (Array.isArray(payload)) return payload;
|
|
757
|
+
return payload && typeof payload === "object" ? [payload] : [];
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
function suggestionApprovalTargets(payload) {
|
|
761
|
+
return writePayloadItems(payload).map((item, index) => {
|
|
762
|
+
if (!item || typeof item !== "object") return `index:${index}`;
|
|
763
|
+
return firstNonEmptyString(
|
|
764
|
+
item.suggestion_id,
|
|
765
|
+
item.id,
|
|
766
|
+
item._id,
|
|
767
|
+
item.mission_id,
|
|
768
|
+
item.target_mission_id,
|
|
769
|
+
item.title ? `${item.change_type || "suggestion"}:${item.title}` : ""
|
|
770
|
+
) || `index:${index}`;
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
function prdApprovalTargets(payload) {
|
|
775
|
+
return writePayloadItems(payload).map((item, index) => {
|
|
776
|
+
if (!item || typeof item !== "object") return `index:${index}`;
|
|
777
|
+
return firstNonEmptyString(item.client_ref, item.title) || `index:${index}`;
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
function requireWriteApproval(args, payload, { operation, artifactKind, targets = [], batchCount = null } = {}) {
|
|
782
|
+
const payloadSha256 = projectApiWritePayloadHash(payload || {});
|
|
783
|
+
const targetValues = normalizeApprovalTargets(targets);
|
|
784
|
+
const expectedBatchCount = batchCount !== null && batchCount !== undefined
|
|
785
|
+
? Number(batchCount)
|
|
786
|
+
: targetValues.length > 1
|
|
787
|
+
? targetValues.length
|
|
788
|
+
: null;
|
|
789
|
+
|
|
790
|
+
if (!isConfirmWrite(args)) {
|
|
791
|
+
console.error("Refusing live Myte write without explicit human approval.");
|
|
792
|
+
console.error(`Operation: ${operation || "unknown"}`);
|
|
793
|
+
console.error(`Payload SHA256: ${payloadSha256}`);
|
|
794
|
+
if (targetValues.length) console.error(`Targets: ${targetValues.join(", ")}`);
|
|
795
|
+
if (expectedBatchCount !== null) console.error(`Batch count: ${expectedBatchCount}`);
|
|
796
|
+
console.error("Create a local .md/.yml/.json approval artifact that lists the exact operation, payload summary, and every target.");
|
|
797
|
+
console.error("Show that artifact to the user and ask for explicit approval.");
|
|
798
|
+
console.error("Then rerun with --confirm-write --approval-artifact <path>.");
|
|
799
|
+
process.exit(1);
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
const artifactPath = resolveWriteApprovalArtifactPath(args);
|
|
803
|
+
if (!artifactPath) {
|
|
804
|
+
console.error("Missing --approval-artifact <path> for approved Myte write.");
|
|
805
|
+
console.error(`Payload SHA256: ${payloadSha256}`);
|
|
806
|
+
console.error("The artifact must be a local .md/.yml/.json file shown to and explicitly approved by the user.");
|
|
807
|
+
process.exit(1);
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
return {
|
|
811
|
+
approved: true,
|
|
812
|
+
source: "explicit_user_approval",
|
|
813
|
+
artifact_path: artifactPath,
|
|
814
|
+
artifact_kind: inferApprovalArtifactKind(artifactPath, artifactKind),
|
|
815
|
+
payload_sha256: payloadSha256,
|
|
816
|
+
targets: targetValues,
|
|
817
|
+
batch_count: expectedBatchCount,
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
function writeApprovalHeaders(writeApproval) {
|
|
822
|
+
if (!writeApproval) return {};
|
|
823
|
+
const headers = {
|
|
824
|
+
"X-Myte-Write-Approval": "explicit_user_approval",
|
|
825
|
+
"X-Myte-Approval-Artifact": String(writeApproval.artifact_path || ""),
|
|
826
|
+
"X-Myte-Approval-Artifact-Kind": String(writeApproval.artifact_kind || ""),
|
|
827
|
+
"X-Myte-Approval-Payload-SHA256": String(writeApproval.payload_sha256 || ""),
|
|
828
|
+
};
|
|
829
|
+
if (writeApproval.batch_count !== null && writeApproval.batch_count !== undefined) {
|
|
830
|
+
headers["X-Myte-Approval-Batch-Count"] = String(writeApproval.batch_count);
|
|
831
|
+
}
|
|
832
|
+
if (Array.isArray(writeApproval.targets) && writeApproval.targets.length) {
|
|
833
|
+
headers["X-Myte-Approval-Targets"] = writeApproval.targets.join(",");
|
|
834
|
+
}
|
|
835
|
+
return headers;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
function formatProjectApiErrorMessage(body, fallback) {
|
|
839
|
+
const message = body?.message || fallback;
|
|
840
|
+
const data = body?.data || {};
|
|
841
|
+
const code = String(data?.code || "");
|
|
842
|
+
if (!code.startsWith("myte_write_approval")) {
|
|
843
|
+
return message;
|
|
844
|
+
}
|
|
845
|
+
const lines = [
|
|
846
|
+
message,
|
|
847
|
+
`Approval error: ${code}`,
|
|
848
|
+
];
|
|
849
|
+
if (data.operation) lines.push(`Operation: ${data.operation}`);
|
|
850
|
+
if (data.payload_sha256) lines.push(`Payload SHA256: ${data.payload_sha256}`);
|
|
851
|
+
if (Array.isArray(data.targets) && data.targets.length) lines.push(`Targets: ${data.targets.join(", ")}`);
|
|
852
|
+
if (data.batch_count !== undefined && data.batch_count !== null) lines.push(`Batch count: ${data.batch_count}`);
|
|
853
|
+
if (Array.isArray(data.required_agent_steps) && data.required_agent_steps.length) {
|
|
854
|
+
lines.push("Required agent steps:");
|
|
855
|
+
for (const step of data.required_agent_steps) {
|
|
856
|
+
lines.push(`- ${step}`);
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
return lines.join("\n");
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
function summarizeDiffDiagnosticsForContext(diagnostics) {
|
|
863
|
+
if (!diagnostics) return null;
|
|
864
|
+
const repos = Array.isArray(diagnostics.repo_summaries)
|
|
865
865
|
? diagnostics.repo_summaries
|
|
866
866
|
: [];
|
|
867
867
|
return {
|
|
@@ -1922,16 +1922,16 @@ async function fetchFeedbackHistory({ apiBase, key, timeoutMs, feedbackId }) {
|
|
|
1922
1922
|
return body.data || {};
|
|
1923
1923
|
}
|
|
1924
1924
|
|
|
1925
|
-
async function postFeedbackRefinement({ apiBase, key, timeoutMs, feedbackId, mode, payload, idempotencyKey, clientSessionId, writeApproval }) {
|
|
1925
|
+
async function postFeedbackRefinement({ apiBase, key, timeoutMs, feedbackId, mode, payload, idempotencyKey, clientSessionId, writeApproval }) {
|
|
1926
1926
|
const fetchFn = await getFetch();
|
|
1927
1927
|
const action = String(mode || "").trim();
|
|
1928
1928
|
const url = `${apiBase}/project-assistant/feedback/${encodeURIComponent(String(feedbackId || ""))}/refinement/${action}`;
|
|
1929
|
-
const headers = {
|
|
1930
|
-
"Content-Type": "application/json",
|
|
1931
|
-
Authorization: `Bearer ${key}`,
|
|
1932
|
-
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
1933
|
-
...writeApprovalHeaders(writeApproval),
|
|
1934
|
-
};
|
|
1929
|
+
const headers = {
|
|
1930
|
+
"Content-Type": "application/json",
|
|
1931
|
+
Authorization: `Bearer ${key}`,
|
|
1932
|
+
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
1933
|
+
...writeApprovalHeaders(writeApproval),
|
|
1934
|
+
};
|
|
1935
1935
|
if (idempotencyKey) {
|
|
1936
1936
|
headers["X-Idempotency-Key"] = String(idempotencyKey).trim();
|
|
1937
1937
|
}
|
|
@@ -1947,7 +1947,7 @@ async function postFeedbackRefinement({ apiBase, key, timeoutMs, feedbackId, mod
|
|
|
1947
1947
|
);
|
|
1948
1948
|
|
|
1949
1949
|
if (!resp.ok || body.status !== "success") {
|
|
1950
|
-
const msg = formatProjectApiErrorMessage(body, `Feedback refinement ${action} failed (${resp.status})`);
|
|
1950
|
+
const msg = formatProjectApiErrorMessage(body, `Feedback refinement ${action} failed (${resp.status})`);
|
|
1951
1951
|
const err = new Error(msg);
|
|
1952
1952
|
err.status = resp.status;
|
|
1953
1953
|
err.data = body?.data;
|
|
@@ -2026,7 +2026,7 @@ async function fetchFeedbackEvents({ apiBase, key, timeoutMs, feedbackId, limit
|
|
|
2026
2026
|
return body.data || {};
|
|
2027
2027
|
}
|
|
2028
2028
|
|
|
2029
|
-
async function postFeedbackReviewSubmission({ apiBase, key, timeoutMs, feedbackId, payload, idempotencyKey, clientSessionId, writeApproval }) {
|
|
2029
|
+
async function postFeedbackReviewSubmission({ apiBase, key, timeoutMs, feedbackId, payload, idempotencyKey, clientSessionId, writeApproval }) {
|
|
2030
2030
|
const fetchFn = await getFetch();
|
|
2031
2031
|
const url = `${apiBase}/project-assistant/feedback/${encodeURIComponent(String(feedbackId || ""))}/refinement/requests`;
|
|
2032
2032
|
const { resp, body } = await fetchJsonWithTimeout(
|
|
@@ -2036,18 +2036,18 @@ async function postFeedbackReviewSubmission({ apiBase, key, timeoutMs, feedbackI
|
|
|
2036
2036
|
method: "POST",
|
|
2037
2037
|
headers: {
|
|
2038
2038
|
"Content-Type": "application/json",
|
|
2039
|
-
Authorization: `Bearer ${key}`,
|
|
2040
|
-
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2041
|
-
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2042
|
-
...writeApprovalHeaders(writeApproval),
|
|
2043
|
-
},
|
|
2039
|
+
Authorization: `Bearer ${key}`,
|
|
2040
|
+
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2041
|
+
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2042
|
+
...writeApprovalHeaders(writeApproval),
|
|
2043
|
+
},
|
|
2044
2044
|
body: JSON.stringify(payload || {}),
|
|
2045
2045
|
},
|
|
2046
2046
|
timeoutMs
|
|
2047
2047
|
);
|
|
2048
2048
|
|
|
2049
2049
|
if (!resp.ok || body.status !== "success") {
|
|
2050
|
-
const msg = formatProjectApiErrorMessage(body, `Feedback review submission failed (${resp.status})`);
|
|
2050
|
+
const msg = formatProjectApiErrorMessage(body, `Feedback review submission failed (${resp.status})`);
|
|
2051
2051
|
const err = new Error(msg);
|
|
2052
2052
|
err.status = resp.status;
|
|
2053
2053
|
err.data = body?.data;
|
|
@@ -2056,7 +2056,7 @@ async function postFeedbackReviewSubmission({ apiBase, key, timeoutMs, feedbackI
|
|
|
2056
2056
|
return body.data || {};
|
|
2057
2057
|
}
|
|
2058
2058
|
|
|
2059
|
-
async function postFeedbackReviewRequestMutation({ apiBase, key, timeoutMs, requestId, endpointAction, payload, idempotencyKey, clientSessionId, writeApproval }) {
|
|
2059
|
+
async function postFeedbackReviewRequestMutation({ apiBase, key, timeoutMs, requestId, endpointAction, payload, idempotencyKey, clientSessionId, writeApproval }) {
|
|
2060
2060
|
const fetchFn = await getFetch();
|
|
2061
2061
|
const url = `${apiBase}/project-assistant/feedback-review-requests/${encodeURIComponent(String(requestId || ""))}/${endpointAction}`;
|
|
2062
2062
|
const { resp, body } = await fetchJsonWithTimeout(
|
|
@@ -2066,18 +2066,18 @@ async function postFeedbackReviewRequestMutation({ apiBase, key, timeoutMs, requ
|
|
|
2066
2066
|
method: "POST",
|
|
2067
2067
|
headers: {
|
|
2068
2068
|
"Content-Type": "application/json",
|
|
2069
|
-
Authorization: `Bearer ${key}`,
|
|
2070
|
-
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2071
|
-
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2072
|
-
...writeApprovalHeaders(writeApproval),
|
|
2073
|
-
},
|
|
2069
|
+
Authorization: `Bearer ${key}`,
|
|
2070
|
+
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2071
|
+
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2072
|
+
...writeApprovalHeaders(writeApproval),
|
|
2073
|
+
},
|
|
2074
2074
|
body: JSON.stringify(payload || {}),
|
|
2075
2075
|
},
|
|
2076
2076
|
timeoutMs
|
|
2077
2077
|
);
|
|
2078
2078
|
|
|
2079
2079
|
if (!resp.ok || body.status !== "success") {
|
|
2080
|
-
const msg = formatProjectApiErrorMessage(body, `Feedback review ${endpointAction} failed (${resp.status})`);
|
|
2080
|
+
const msg = formatProjectApiErrorMessage(body, `Feedback review ${endpointAction} failed (${resp.status})`);
|
|
2081
2081
|
const err = new Error(msg);
|
|
2082
2082
|
err.status = resp.status;
|
|
2083
2083
|
err.data = body?.data;
|
|
@@ -2086,7 +2086,7 @@ async function postFeedbackReviewRequestMutation({ apiBase, key, timeoutMs, requ
|
|
|
2086
2086
|
return body.data || {};
|
|
2087
2087
|
}
|
|
2088
2088
|
|
|
2089
|
-
async function postFeedbackBatchReviewMutation({ apiBase, key, timeoutMs, payload, idempotencyKey, clientSessionId, writeApproval }) {
|
|
2089
|
+
async function postFeedbackBatchReviewMutation({ apiBase, key, timeoutMs, payload, idempotencyKey, clientSessionId, writeApproval }) {
|
|
2090
2090
|
const fetchFn = await getFetch();
|
|
2091
2091
|
const url = `${apiBase}/project-assistant/feedback-review-requests/batch-review`;
|
|
2092
2092
|
const { resp, body } = await fetchJsonWithTimeout(
|
|
@@ -2096,18 +2096,18 @@ async function postFeedbackBatchReviewMutation({ apiBase, key, timeoutMs, payloa
|
|
|
2096
2096
|
method: "POST",
|
|
2097
2097
|
headers: {
|
|
2098
2098
|
"Content-Type": "application/json",
|
|
2099
|
-
Authorization: `Bearer ${key}`,
|
|
2100
|
-
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2101
|
-
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2102
|
-
...writeApprovalHeaders(writeApproval),
|
|
2103
|
-
},
|
|
2099
|
+
Authorization: `Bearer ${key}`,
|
|
2100
|
+
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2101
|
+
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2102
|
+
...writeApprovalHeaders(writeApproval),
|
|
2103
|
+
},
|
|
2104
2104
|
body: JSON.stringify(payload || {}),
|
|
2105
2105
|
},
|
|
2106
2106
|
timeoutMs
|
|
2107
2107
|
);
|
|
2108
2108
|
|
|
2109
2109
|
if (!resp.ok || body.status !== "success") {
|
|
2110
|
-
const msg = formatProjectApiErrorMessage(body, `Feedback batch review failed (${resp.status})`);
|
|
2110
|
+
const msg = formatProjectApiErrorMessage(body, `Feedback batch review failed (${resp.status})`);
|
|
2111
2111
|
const err = new Error(msg);
|
|
2112
2112
|
err.status = resp.status;
|
|
2113
2113
|
err.data = body?.data;
|
|
@@ -2116,7 +2116,7 @@ async function postFeedbackBatchReviewMutation({ apiBase, key, timeoutMs, payloa
|
|
|
2116
2116
|
return body.data || {};
|
|
2117
2117
|
}
|
|
2118
2118
|
|
|
2119
|
-
async function postFeedbackBoardMutation({ apiBase, key, timeoutMs, feedbackId, endpoint, payload, idempotencyKey, clientSessionId, writeApproval }) {
|
|
2119
|
+
async function postFeedbackBoardMutation({ apiBase, key, timeoutMs, feedbackId, endpoint, payload, idempotencyKey, clientSessionId, writeApproval }) {
|
|
2120
2120
|
const fetchFn = await getFetch();
|
|
2121
2121
|
const url = `${apiBase}/project-assistant/feedback/${encodeURIComponent(String(feedbackId || ""))}/${endpoint}`;
|
|
2122
2122
|
const { resp, body } = await fetchJsonWithTimeout(
|
|
@@ -2126,18 +2126,18 @@ async function postFeedbackBoardMutation({ apiBase, key, timeoutMs, feedbackId,
|
|
|
2126
2126
|
method: "POST",
|
|
2127
2127
|
headers: {
|
|
2128
2128
|
"Content-Type": "application/json",
|
|
2129
|
-
Authorization: `Bearer ${key}`,
|
|
2130
|
-
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2131
|
-
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2132
|
-
...writeApprovalHeaders(writeApproval),
|
|
2133
|
-
},
|
|
2129
|
+
Authorization: `Bearer ${key}`,
|
|
2130
|
+
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2131
|
+
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2132
|
+
...writeApprovalHeaders(writeApproval),
|
|
2133
|
+
},
|
|
2134
2134
|
body: JSON.stringify(payload || {}),
|
|
2135
2135
|
},
|
|
2136
2136
|
timeoutMs
|
|
2137
2137
|
);
|
|
2138
2138
|
|
|
2139
2139
|
if (!resp.ok || body.status !== "success") {
|
|
2140
|
-
const msg = formatProjectApiErrorMessage(body, `Feedback board mutation failed (${resp.status})`);
|
|
2140
|
+
const msg = formatProjectApiErrorMessage(body, `Feedback board mutation failed (${resp.status})`);
|
|
2141
2141
|
const err = new Error(msg);
|
|
2142
2142
|
err.status = resp.status;
|
|
2143
2143
|
err.data = body?.data;
|
|
@@ -2146,7 +2146,7 @@ async function postFeedbackBoardMutation({ apiBase, key, timeoutMs, feedbackId,
|
|
|
2146
2146
|
return body.data || {};
|
|
2147
2147
|
}
|
|
2148
2148
|
|
|
2149
|
-
async function postFeedbackBatchBoardMutation({ apiBase, key, timeoutMs, payload, idempotencyKey, clientSessionId, writeApproval }) {
|
|
2149
|
+
async function postFeedbackBatchBoardMutation({ apiBase, key, timeoutMs, payload, idempotencyKey, clientSessionId, writeApproval }) {
|
|
2150
2150
|
const fetchFn = await getFetch();
|
|
2151
2151
|
const url = `${apiBase}/project-assistant/feedback/batch-board-move`;
|
|
2152
2152
|
const { resp, body } = await fetchJsonWithTimeout(
|
|
@@ -2156,57 +2156,57 @@ async function postFeedbackBatchBoardMutation({ apiBase, key, timeoutMs, payload
|
|
|
2156
2156
|
method: "POST",
|
|
2157
2157
|
headers: {
|
|
2158
2158
|
"Content-Type": "application/json",
|
|
2159
|
-
Authorization: `Bearer ${key}`,
|
|
2160
|
-
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2161
|
-
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2162
|
-
...writeApprovalHeaders(writeApproval),
|
|
2163
|
-
},
|
|
2159
|
+
Authorization: `Bearer ${key}`,
|
|
2160
|
+
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2161
|
+
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2162
|
+
...writeApprovalHeaders(writeApproval),
|
|
2163
|
+
},
|
|
2164
2164
|
body: JSON.stringify(payload || {}),
|
|
2165
2165
|
},
|
|
2166
2166
|
timeoutMs
|
|
2167
2167
|
);
|
|
2168
2168
|
|
|
2169
2169
|
if (!resp.ok || body.status !== "success") {
|
|
2170
|
-
const msg = formatProjectApiErrorMessage(body, `Feedback batch board mutation failed (${resp.status})`);
|
|
2170
|
+
const msg = formatProjectApiErrorMessage(body, `Feedback batch board mutation failed (${resp.status})`);
|
|
2171
2171
|
const err = new Error(msg);
|
|
2172
2172
|
err.status = resp.status;
|
|
2173
2173
|
err.data = body?.data;
|
|
2174
2174
|
throw err;
|
|
2175
2175
|
}
|
|
2176
|
-
return body.data || {};
|
|
2177
|
-
}
|
|
2178
|
-
|
|
2179
|
-
async function postFeedbackComment({ apiBase, key, timeoutMs, feedbackId, payload, idempotencyKey, clientSessionId, writeApproval }) {
|
|
2180
|
-
const fetchFn = await getFetch();
|
|
2181
|
-
const url = `${apiBase}/project-assistant/feedback/${encodeURIComponent(String(feedbackId || ""))}/comments`;
|
|
2182
|
-
const { resp, body } = await fetchJsonWithTimeout(
|
|
2183
|
-
fetchFn,
|
|
2184
|
-
url,
|
|
2185
|
-
{
|
|
2186
|
-
method: "POST",
|
|
2187
|
-
headers: {
|
|
2188
|
-
"Content-Type": "application/json",
|
|
2189
|
-
Authorization: `Bearer ${key}`,
|
|
2190
|
-
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2191
|
-
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2192
|
-
...writeApprovalHeaders(writeApproval),
|
|
2193
|
-
},
|
|
2194
|
-
body: JSON.stringify(payload || {}),
|
|
2195
|
-
},
|
|
2196
|
-
timeoutMs
|
|
2197
|
-
);
|
|
2198
|
-
|
|
2199
|
-
if (!resp.ok || body.status !== "success") {
|
|
2200
|
-
const msg = formatProjectApiErrorMessage(body, `Feedback comment failed (${resp.status})`);
|
|
2201
|
-
const err = new Error(msg);
|
|
2202
|
-
err.status = resp.status;
|
|
2203
|
-
err.data = body?.data;
|
|
2204
|
-
throw err;
|
|
2205
|
-
}
|
|
2206
|
-
return body.data || {};
|
|
2207
|
-
}
|
|
2208
|
-
|
|
2209
|
-
async function fetchFeedbackPrdVersions({ apiBase, key, timeoutMs, feedbackId }) {
|
|
2176
|
+
return body.data || {};
|
|
2177
|
+
}
|
|
2178
|
+
|
|
2179
|
+
async function postFeedbackComment({ apiBase, key, timeoutMs, feedbackId, payload, idempotencyKey, clientSessionId, writeApproval }) {
|
|
2180
|
+
const fetchFn = await getFetch();
|
|
2181
|
+
const url = `${apiBase}/project-assistant/feedback/${encodeURIComponent(String(feedbackId || ""))}/comments`;
|
|
2182
|
+
const { resp, body } = await fetchJsonWithTimeout(
|
|
2183
|
+
fetchFn,
|
|
2184
|
+
url,
|
|
2185
|
+
{
|
|
2186
|
+
method: "POST",
|
|
2187
|
+
headers: {
|
|
2188
|
+
"Content-Type": "application/json",
|
|
2189
|
+
Authorization: `Bearer ${key}`,
|
|
2190
|
+
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2191
|
+
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2192
|
+
...writeApprovalHeaders(writeApproval),
|
|
2193
|
+
},
|
|
2194
|
+
body: JSON.stringify(payload || {}),
|
|
2195
|
+
},
|
|
2196
|
+
timeoutMs
|
|
2197
|
+
);
|
|
2198
|
+
|
|
2199
|
+
if (!resp.ok || body.status !== "success") {
|
|
2200
|
+
const msg = formatProjectApiErrorMessage(body, `Feedback comment failed (${resp.status})`);
|
|
2201
|
+
const err = new Error(msg);
|
|
2202
|
+
err.status = resp.status;
|
|
2203
|
+
err.data = body?.data;
|
|
2204
|
+
throw err;
|
|
2205
|
+
}
|
|
2206
|
+
return body.data || {};
|
|
2207
|
+
}
|
|
2208
|
+
|
|
2209
|
+
async function fetchFeedbackPrdVersions({ apiBase, key, timeoutMs, feedbackId }) {
|
|
2210
2210
|
const fetchFn = await getFetch();
|
|
2211
2211
|
const url = `${apiBase}/project-assistant/feedback/${encodeURIComponent(String(feedbackId || ""))}/prd/versions`;
|
|
2212
2212
|
const { resp, body } = await fetchJsonWithTimeout(
|
|
@@ -2303,7 +2303,7 @@ function resolveProjectMutationIdempotencyKey({ args, operation, payload }) {
|
|
|
2303
2303
|
return createHash("sha256").update(fingerprint).digest("hex");
|
|
2304
2304
|
}
|
|
2305
2305
|
|
|
2306
|
-
async function postSuggestionsMutation({ apiBase, key, timeoutMs, endpoint, payload, idempotencyKey, clientSessionId, writeApproval }) {
|
|
2306
|
+
async function postSuggestionsMutation({ apiBase, key, timeoutMs, endpoint, payload, idempotencyKey, clientSessionId, writeApproval }) {
|
|
2307
2307
|
const fetchFn = await getFetch();
|
|
2308
2308
|
const url = `${apiBase}${endpoint}`;
|
|
2309
2309
|
const { resp, body } = await fetchJsonWithTimeout(
|
|
@@ -2313,27 +2313,27 @@ async function postSuggestionsMutation({ apiBase, key, timeoutMs, endpoint, payl
|
|
|
2313
2313
|
method: "POST",
|
|
2314
2314
|
headers: {
|
|
2315
2315
|
"Content-Type": "application/json",
|
|
2316
|
-
Authorization: `Bearer ${key}`,
|
|
2317
|
-
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2318
|
-
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2319
|
-
...writeApprovalHeaders(writeApproval),
|
|
2320
|
-
},
|
|
2316
|
+
Authorization: `Bearer ${key}`,
|
|
2317
|
+
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2318
|
+
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2319
|
+
...writeApprovalHeaders(writeApproval),
|
|
2320
|
+
},
|
|
2321
2321
|
body: JSON.stringify(payload),
|
|
2322
2322
|
},
|
|
2323
2323
|
timeoutMs
|
|
2324
2324
|
);
|
|
2325
2325
|
|
|
2326
2326
|
if (!resp.ok || body.status !== "success") {
|
|
2327
|
-
const msg = formatProjectApiErrorMessage(body, `Mission suggestions request failed (${resp.status})`);
|
|
2328
|
-
const err = new Error(msg);
|
|
2329
|
-
err.status = resp.status;
|
|
2330
|
-
err.data = body?.data;
|
|
2327
|
+
const msg = formatProjectApiErrorMessage(body, `Mission suggestions request failed (${resp.status})`);
|
|
2328
|
+
const err = new Error(msg);
|
|
2329
|
+
err.status = resp.status;
|
|
2330
|
+
err.data = body?.data;
|
|
2331
2331
|
throw err;
|
|
2332
2332
|
}
|
|
2333
2333
|
return body.data || {};
|
|
2334
2334
|
}
|
|
2335
2335
|
|
|
2336
|
-
async function createRunQaqcBatch({ apiBase, key, timeoutMs, payload, idempotencyKey, clientSessionId, writeApproval }) {
|
|
2336
|
+
async function createRunQaqcBatch({ apiBase, key, timeoutMs, payload, idempotencyKey, clientSessionId, writeApproval }) {
|
|
2337
2337
|
const fetchFn = await getFetch();
|
|
2338
2338
|
const url = `${apiBase}/project-assistant/run-qaqc`;
|
|
2339
2339
|
const { resp, body } = await fetchJsonWithTimeout(
|
|
@@ -2343,27 +2343,27 @@ async function createRunQaqcBatch({ apiBase, key, timeoutMs, payload, idempotenc
|
|
|
2343
2343
|
method: "POST",
|
|
2344
2344
|
headers: {
|
|
2345
2345
|
"Content-Type": "application/json",
|
|
2346
|
-
Authorization: `Bearer ${key}`,
|
|
2347
|
-
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2348
|
-
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2349
|
-
...writeApprovalHeaders(writeApproval),
|
|
2350
|
-
},
|
|
2346
|
+
Authorization: `Bearer ${key}`,
|
|
2347
|
+
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2348
|
+
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2349
|
+
...writeApprovalHeaders(writeApproval),
|
|
2350
|
+
},
|
|
2351
2351
|
body: JSON.stringify(payload),
|
|
2352
2352
|
},
|
|
2353
2353
|
timeoutMs
|
|
2354
2354
|
);
|
|
2355
2355
|
|
|
2356
2356
|
if (!resp.ok || body.status !== "success") {
|
|
2357
|
-
const msg = formatProjectApiErrorMessage(body, `Run QAQC request failed (${resp.status})`);
|
|
2358
|
-
const err = new Error(msg);
|
|
2359
|
-
err.status = resp.status;
|
|
2360
|
-
err.data = body?.data;
|
|
2361
|
-
throw err;
|
|
2362
|
-
}
|
|
2357
|
+
const msg = formatProjectApiErrorMessage(body, `Run QAQC request failed (${resp.status})`);
|
|
2358
|
+
const err = new Error(msg);
|
|
2359
|
+
err.status = resp.status;
|
|
2360
|
+
err.data = body?.data;
|
|
2361
|
+
throw err;
|
|
2362
|
+
}
|
|
2363
2363
|
return body.data || {};
|
|
2364
2364
|
}
|
|
2365
2365
|
|
|
2366
|
-
async function createMissionStatusUpdate({ apiBase, key, timeoutMs, payload, idempotencyKey, clientSessionId, writeApproval }) {
|
|
2366
|
+
async function createMissionStatusUpdate({ apiBase, key, timeoutMs, payload, idempotencyKey, clientSessionId, writeApproval }) {
|
|
2367
2367
|
const fetchFn = await getFetch();
|
|
2368
2368
|
const url = `${apiBase}/project-assistant/mission-status-update`;
|
|
2369
2369
|
const { resp, body } = await fetchJsonWithTimeout(
|
|
@@ -2373,27 +2373,27 @@ async function createMissionStatusUpdate({ apiBase, key, timeoutMs, payload, ide
|
|
|
2373
2373
|
method: "POST",
|
|
2374
2374
|
headers: {
|
|
2375
2375
|
"Content-Type": "application/json",
|
|
2376
|
-
Authorization: `Bearer ${key}`,
|
|
2377
|
-
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2378
|
-
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2379
|
-
...writeApprovalHeaders(writeApproval),
|
|
2380
|
-
},
|
|
2376
|
+
Authorization: `Bearer ${key}`,
|
|
2377
|
+
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2378
|
+
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2379
|
+
...writeApprovalHeaders(writeApproval),
|
|
2380
|
+
},
|
|
2381
2381
|
body: JSON.stringify(payload),
|
|
2382
2382
|
},
|
|
2383
2383
|
timeoutMs
|
|
2384
2384
|
);
|
|
2385
2385
|
|
|
2386
2386
|
if (!resp.ok || body.status !== "success") {
|
|
2387
|
-
const msg = formatProjectApiErrorMessage(body, `Mission status update request failed (${resp.status})`);
|
|
2388
|
-
const err = new Error(msg);
|
|
2389
|
-
err.status = resp.status;
|
|
2390
|
-
err.data = body?.data;
|
|
2391
|
-
throw err;
|
|
2392
|
-
}
|
|
2387
|
+
const msg = formatProjectApiErrorMessage(body, `Mission status update request failed (${resp.status})`);
|
|
2388
|
+
const err = new Error(msg);
|
|
2389
|
+
err.status = resp.status;
|
|
2390
|
+
err.data = body?.data;
|
|
2391
|
+
throw err;
|
|
2392
|
+
}
|
|
2393
2393
|
return body.data || {};
|
|
2394
2394
|
}
|
|
2395
2395
|
|
|
2396
|
-
async function createMissionArchiveUpdate({ apiBase, key, timeoutMs, endpoint, payload, idempotencyKey, clientSessionId, writeApproval }) {
|
|
2396
|
+
async function createMissionArchiveUpdate({ apiBase, key, timeoutMs, endpoint, payload, idempotencyKey, clientSessionId, writeApproval }) {
|
|
2397
2397
|
const fetchFn = await getFetch();
|
|
2398
2398
|
const url = `${apiBase}${endpoint}`;
|
|
2399
2399
|
const { resp, body } = await fetchJsonWithTimeout(
|
|
@@ -2403,21 +2403,21 @@ async function createMissionArchiveUpdate({ apiBase, key, timeoutMs, endpoint, p
|
|
|
2403
2403
|
method: "POST",
|
|
2404
2404
|
headers: {
|
|
2405
2405
|
"Content-Type": "application/json",
|
|
2406
|
-
Authorization: `Bearer ${key}`,
|
|
2407
|
-
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2408
|
-
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2409
|
-
...writeApprovalHeaders(writeApproval),
|
|
2410
|
-
},
|
|
2406
|
+
Authorization: `Bearer ${key}`,
|
|
2407
|
+
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2408
|
+
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2409
|
+
...writeApprovalHeaders(writeApproval),
|
|
2410
|
+
},
|
|
2411
2411
|
body: JSON.stringify(payload),
|
|
2412
2412
|
},
|
|
2413
2413
|
timeoutMs
|
|
2414
2414
|
);
|
|
2415
2415
|
|
|
2416
2416
|
if (!resp.ok || body.status !== "success") {
|
|
2417
|
-
const msg = formatProjectApiErrorMessage(body, `Mission archive request failed (${resp.status})`);
|
|
2418
|
-
const err = new Error(msg);
|
|
2419
|
-
err.status = resp.status;
|
|
2420
|
-
err.data = body?.data;
|
|
2417
|
+
const msg = formatProjectApiErrorMessage(body, `Mission archive request failed (${resp.status})`);
|
|
2418
|
+
const err = new Error(msg);
|
|
2419
|
+
err.status = resp.status;
|
|
2420
|
+
err.data = body?.data;
|
|
2421
2421
|
throw err;
|
|
2422
2422
|
}
|
|
2423
2423
|
return body.data || {};
|
|
@@ -2547,28 +2547,28 @@ async function runRunQaqc(args) {
|
|
|
2547
2547
|
return;
|
|
2548
2548
|
}
|
|
2549
2549
|
|
|
2550
|
-
const timeoutMs = resolveTimeoutMs(args);
|
|
2551
|
-
const apiBase = resolveApiBase(args);
|
|
2552
|
-
const shouldWait = Boolean(args.wait || args.sync);
|
|
2553
|
-
const shouldSync = Boolean(args.sync);
|
|
2554
|
-
const writeApproval = requireWriteApproval(args, payload, {
|
|
2555
|
-
operation: "run-qaqc",
|
|
2556
|
-
artifactKind: "yaml",
|
|
2557
|
-
targets: missionIds,
|
|
2558
|
-
batchCount: missionIds.length,
|
|
2559
|
-
});
|
|
2560
|
-
|
|
2561
|
-
let data;
|
|
2562
|
-
try {
|
|
2563
|
-
data = await createRunQaqcBatch({
|
|
2564
|
-
apiBase,
|
|
2550
|
+
const timeoutMs = resolveTimeoutMs(args);
|
|
2551
|
+
const apiBase = resolveApiBase(args);
|
|
2552
|
+
const shouldWait = Boolean(args.wait || args.sync);
|
|
2553
|
+
const shouldSync = Boolean(args.sync);
|
|
2554
|
+
const writeApproval = requireWriteApproval(args, payload, {
|
|
2555
|
+
operation: "run-qaqc",
|
|
2556
|
+
artifactKind: "yaml",
|
|
2557
|
+
targets: missionIds,
|
|
2558
|
+
batchCount: missionIds.length,
|
|
2559
|
+
});
|
|
2560
|
+
|
|
2561
|
+
let data;
|
|
2562
|
+
try {
|
|
2563
|
+
data = await createRunQaqcBatch({
|
|
2564
|
+
apiBase,
|
|
2565
2565
|
key,
|
|
2566
2566
|
timeoutMs,
|
|
2567
|
-
payload,
|
|
2568
|
-
idempotencyKey,
|
|
2569
|
-
clientSessionId,
|
|
2570
|
-
writeApproval,
|
|
2571
|
-
});
|
|
2567
|
+
payload,
|
|
2568
|
+
idempotencyKey,
|
|
2569
|
+
clientSessionId,
|
|
2570
|
+
writeApproval,
|
|
2571
|
+
});
|
|
2572
2572
|
} catch (err) {
|
|
2573
2573
|
if (err?.name === "AbortError") {
|
|
2574
2574
|
console.error(`Request timed out after ${timeoutMs}ms`);
|
|
@@ -2709,26 +2709,26 @@ async function runMissionStatus(args) {
|
|
|
2709
2709
|
return;
|
|
2710
2710
|
}
|
|
2711
2711
|
|
|
2712
|
-
const timeoutMs = resolveTimeoutMs(args);
|
|
2713
|
-
const apiBase = resolveApiBase(args);
|
|
2714
|
-
const writeApproval = requireWriteApproval(args, payload, {
|
|
2715
|
-
operation: "mission-status-update",
|
|
2716
|
-
artifactKind: "yaml",
|
|
2717
|
-
targets: missionIds,
|
|
2718
|
-
batchCount: missionIds.length,
|
|
2719
|
-
});
|
|
2720
|
-
|
|
2721
|
-
let data;
|
|
2722
|
-
try {
|
|
2723
|
-
data = await createMissionStatusUpdate({
|
|
2724
|
-
apiBase,
|
|
2712
|
+
const timeoutMs = resolveTimeoutMs(args);
|
|
2713
|
+
const apiBase = resolveApiBase(args);
|
|
2714
|
+
const writeApproval = requireWriteApproval(args, payload, {
|
|
2715
|
+
operation: "mission-status-update",
|
|
2716
|
+
artifactKind: "yaml",
|
|
2717
|
+
targets: missionIds,
|
|
2718
|
+
batchCount: missionIds.length,
|
|
2719
|
+
});
|
|
2720
|
+
|
|
2721
|
+
let data;
|
|
2722
|
+
try {
|
|
2723
|
+
data = await createMissionStatusUpdate({
|
|
2724
|
+
apiBase,
|
|
2725
2725
|
key,
|
|
2726
2726
|
timeoutMs,
|
|
2727
|
-
payload,
|
|
2728
|
-
idempotencyKey,
|
|
2729
|
-
clientSessionId,
|
|
2730
|
-
writeApproval,
|
|
2731
|
-
});
|
|
2727
|
+
payload,
|
|
2728
|
+
idempotencyKey,
|
|
2729
|
+
clientSessionId,
|
|
2730
|
+
writeApproval,
|
|
2731
|
+
});
|
|
2732
2732
|
} catch (err) {
|
|
2733
2733
|
if (err?.name === "AbortError") {
|
|
2734
2734
|
console.error(`Request timed out after ${timeoutMs}ms`);
|
|
@@ -2822,28 +2822,28 @@ async function runMissionArchiveCommand(args) {
|
|
|
2822
2822
|
return;
|
|
2823
2823
|
}
|
|
2824
2824
|
|
|
2825
|
-
const timeoutMs = resolveTimeoutMs(args);
|
|
2826
|
-
const apiBase = resolveApiBase(args);
|
|
2827
|
-
const endpoint = "/project-assistant/mission-archive";
|
|
2828
|
-
const writeApproval = requireWriteApproval(args, payload, {
|
|
2829
|
-
operation: "mission-archive",
|
|
2830
|
-
artifactKind: "yaml",
|
|
2831
|
-
targets: missionIds,
|
|
2832
|
-
batchCount: missionIds.length,
|
|
2833
|
-
});
|
|
2834
|
-
|
|
2835
|
-
let data;
|
|
2836
|
-
try {
|
|
2837
|
-
data = await createMissionArchiveUpdate({
|
|
2838
|
-
apiBase,
|
|
2825
|
+
const timeoutMs = resolveTimeoutMs(args);
|
|
2826
|
+
const apiBase = resolveApiBase(args);
|
|
2827
|
+
const endpoint = "/project-assistant/mission-archive";
|
|
2828
|
+
const writeApproval = requireWriteApproval(args, payload, {
|
|
2829
|
+
operation: "mission-archive",
|
|
2830
|
+
artifactKind: "yaml",
|
|
2831
|
+
targets: missionIds,
|
|
2832
|
+
batchCount: missionIds.length,
|
|
2833
|
+
});
|
|
2834
|
+
|
|
2835
|
+
let data;
|
|
2836
|
+
try {
|
|
2837
|
+
data = await createMissionArchiveUpdate({
|
|
2838
|
+
apiBase,
|
|
2839
2839
|
key,
|
|
2840
2840
|
timeoutMs,
|
|
2841
2841
|
endpoint,
|
|
2842
|
-
payload,
|
|
2843
|
-
idempotencyKey,
|
|
2844
|
-
clientSessionId,
|
|
2845
|
-
writeApproval,
|
|
2846
|
-
});
|
|
2842
|
+
payload,
|
|
2843
|
+
idempotencyKey,
|
|
2844
|
+
clientSessionId,
|
|
2845
|
+
writeApproval,
|
|
2846
|
+
});
|
|
2847
2847
|
} catch (err) {
|
|
2848
2848
|
if (err?.name === "AbortError") {
|
|
2849
2849
|
console.error(`Request timed out after ${timeoutMs}ms`);
|
|
@@ -2937,28 +2937,28 @@ async function runUpdateTeam(args) {
|
|
|
2937
2937
|
const apiBase = resolveApiBase(args);
|
|
2938
2938
|
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id);
|
|
2939
2939
|
if (clientSessionId) payload.client_session_id = clientSessionId;
|
|
2940
|
-
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
2941
|
-
args,
|
|
2942
|
-
operation: "update_team",
|
|
2943
|
-
payload,
|
|
2944
|
-
});
|
|
2945
|
-
const writeApproval = requireWriteApproval(args, payload, {
|
|
2946
|
-
operation: "update_team",
|
|
2947
|
-
artifactKind: "markdown",
|
|
2948
|
-
});
|
|
2949
|
-
|
|
2950
|
-
let data;
|
|
2951
|
-
try {
|
|
2952
|
-
data = await postSuggestionsMutation({
|
|
2940
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
2941
|
+
args,
|
|
2942
|
+
operation: "update_team",
|
|
2943
|
+
payload,
|
|
2944
|
+
});
|
|
2945
|
+
const writeApproval = requireWriteApproval(args, payload, {
|
|
2946
|
+
operation: "update_team",
|
|
2947
|
+
artifactKind: "markdown",
|
|
2948
|
+
});
|
|
2949
|
+
|
|
2950
|
+
let data;
|
|
2951
|
+
try {
|
|
2952
|
+
data = await postSuggestionsMutation({
|
|
2953
2953
|
apiBase,
|
|
2954
2954
|
key,
|
|
2955
2955
|
payload,
|
|
2956
2956
|
timeoutMs,
|
|
2957
|
-
endpoint: "/project-assistant/project-comment",
|
|
2958
|
-
idempotencyKey,
|
|
2959
|
-
clientSessionId,
|
|
2960
|
-
writeApproval,
|
|
2961
|
-
});
|
|
2957
|
+
endpoint: "/project-assistant/project-comment",
|
|
2958
|
+
idempotencyKey,
|
|
2959
|
+
clientSessionId,
|
|
2960
|
+
writeApproval,
|
|
2961
|
+
});
|
|
2962
2962
|
} catch (err) {
|
|
2963
2963
|
if (err?.name === "AbortError") {
|
|
2964
2964
|
console.error(`Request timed out after ${timeoutMs}ms`);
|
|
@@ -3011,28 +3011,28 @@ async function runUpdateOwner(args) {
|
|
|
3011
3011
|
const apiBase = resolveApiBase(args);
|
|
3012
3012
|
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id);
|
|
3013
3013
|
if (clientSessionId) payload.client_session_id = clientSessionId;
|
|
3014
|
-
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
3015
|
-
args,
|
|
3016
|
-
operation: "update_owner",
|
|
3017
|
-
payload,
|
|
3018
|
-
});
|
|
3019
|
-
const writeApproval = requireWriteApproval(args, payload, {
|
|
3020
|
-
operation: "update_owner",
|
|
3021
|
-
artifactKind: "markdown",
|
|
3022
|
-
});
|
|
3023
|
-
|
|
3024
|
-
let data;
|
|
3025
|
-
try {
|
|
3014
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
3015
|
+
args,
|
|
3016
|
+
operation: "update_owner",
|
|
3017
|
+
payload,
|
|
3018
|
+
});
|
|
3019
|
+
const writeApproval = requireWriteApproval(args, payload, {
|
|
3020
|
+
operation: "update_owner",
|
|
3021
|
+
artifactKind: "markdown",
|
|
3022
|
+
});
|
|
3023
|
+
|
|
3024
|
+
let data;
|
|
3025
|
+
try {
|
|
3026
3026
|
data = await postSuggestionsMutation({
|
|
3027
3027
|
apiBase,
|
|
3028
3028
|
key,
|
|
3029
3029
|
payload,
|
|
3030
3030
|
timeoutMs,
|
|
3031
|
-
endpoint: "/project-assistant/update-owner",
|
|
3032
|
-
idempotencyKey,
|
|
3033
|
-
clientSessionId,
|
|
3034
|
-
writeApproval,
|
|
3035
|
-
});
|
|
3031
|
+
endpoint: "/project-assistant/update-owner",
|
|
3032
|
+
idempotencyKey,
|
|
3033
|
+
clientSessionId,
|
|
3034
|
+
writeApproval,
|
|
3035
|
+
});
|
|
3036
3036
|
} catch (err) {
|
|
3037
3037
|
if (err?.name === "AbortError") {
|
|
3038
3038
|
console.error(`Request timed out after ${timeoutMs}ms`);
|
|
@@ -3094,28 +3094,28 @@ async function runUpdateClient(args) {
|
|
|
3094
3094
|
const apiBase = resolveApiBase(args);
|
|
3095
3095
|
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id);
|
|
3096
3096
|
if (clientSessionId) payload.client_session_id = clientSessionId;
|
|
3097
|
-
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
3098
|
-
args,
|
|
3099
|
-
operation: "update_client",
|
|
3100
|
-
payload,
|
|
3101
|
-
});
|
|
3102
|
-
const writeApproval = requireWriteApproval(args, payload, {
|
|
3103
|
-
operation: "update_client",
|
|
3104
|
-
artifactKind: "markdown",
|
|
3105
|
-
});
|
|
3106
|
-
|
|
3107
|
-
let data;
|
|
3108
|
-
try {
|
|
3097
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
3098
|
+
args,
|
|
3099
|
+
operation: "update_client",
|
|
3100
|
+
payload,
|
|
3101
|
+
});
|
|
3102
|
+
const writeApproval = requireWriteApproval(args, payload, {
|
|
3103
|
+
operation: "update_client",
|
|
3104
|
+
artifactKind: "markdown",
|
|
3105
|
+
});
|
|
3106
|
+
|
|
3107
|
+
let data;
|
|
3108
|
+
try {
|
|
3109
3109
|
data = await postSuggestionsMutation({
|
|
3110
3110
|
apiBase,
|
|
3111
3111
|
key,
|
|
3112
3112
|
payload,
|
|
3113
3113
|
timeoutMs,
|
|
3114
|
-
endpoint: "/project-assistant/client-update-drafts",
|
|
3115
|
-
idempotencyKey,
|
|
3116
|
-
clientSessionId,
|
|
3117
|
-
writeApproval,
|
|
3118
|
-
});
|
|
3114
|
+
endpoint: "/project-assistant/client-update-drafts",
|
|
3115
|
+
idempotencyKey,
|
|
3116
|
+
clientSessionId,
|
|
3117
|
+
writeApproval,
|
|
3118
|
+
});
|
|
3119
3119
|
} catch (err) {
|
|
3120
3120
|
if (err?.name === "AbortError") {
|
|
3121
3121
|
console.error(`Request timed out after ${timeoutMs}ms`);
|
|
@@ -3207,20 +3207,48 @@ function stringifyYaml(value) {
|
|
|
3207
3207
|
return `${JSON.stringify(value, null, 2)}\n`;
|
|
3208
3208
|
}
|
|
3209
3209
|
|
|
3210
|
-
function stableJsonStringify(value) {
|
|
3211
|
-
if (Array.isArray(value)) {
|
|
3212
|
-
return `[${value.map((item) => stableJsonStringify(item)).join(",")}]`;
|
|
3210
|
+
function stableJsonStringify(value) {
|
|
3211
|
+
if (Array.isArray(value)) {
|
|
3212
|
+
return `[${value.map((item) => stableJsonStringify(item)).join(",")}]`;
|
|
3213
3213
|
}
|
|
3214
3214
|
if (value && typeof value === "object") {
|
|
3215
3215
|
const entries = Object.keys(value)
|
|
3216
3216
|
.sort()
|
|
3217
3217
|
.map((key) => `${JSON.stringify(key)}:${stableJsonStringify(value[key])}`);
|
|
3218
3218
|
return `{${entries.join(",")}}`;
|
|
3219
|
-
}
|
|
3220
|
-
return JSON.stringify(value);
|
|
3221
|
-
}
|
|
3222
|
-
|
|
3223
|
-
function
|
|
3219
|
+
}
|
|
3220
|
+
return JSON.stringify(value);
|
|
3221
|
+
}
|
|
3222
|
+
|
|
3223
|
+
function jsonStringifyEnsureAscii(value) {
|
|
3224
|
+
return JSON.stringify(String(value)).replace(/[^\x00-\x7F]/g, (char) => {
|
|
3225
|
+
const code = char.charCodeAt(0);
|
|
3226
|
+
return `\\u${code.toString(16).padStart(4, "0")}`;
|
|
3227
|
+
});
|
|
3228
|
+
}
|
|
3229
|
+
|
|
3230
|
+
function pythonJsonDumpsCompatible(value) {
|
|
3231
|
+
if (Array.isArray(value)) {
|
|
3232
|
+
return `[${value.map((item) => pythonJsonDumpsCompatible(item)).join(", ")}]`;
|
|
3233
|
+
}
|
|
3234
|
+
if (value && typeof value === "object") {
|
|
3235
|
+
const entries = Object.keys(value)
|
|
3236
|
+
.sort()
|
|
3237
|
+
.map((key) => `${jsonStringifyEnsureAscii(key)}: ${pythonJsonDumpsCompatible(value[key])}`);
|
|
3238
|
+
return `{${entries.join(", ")}}`;
|
|
3239
|
+
}
|
|
3240
|
+
if (value === null) return "null";
|
|
3241
|
+
if (typeof value === "boolean") return value ? "true" : "false";
|
|
3242
|
+
if (typeof value === "number") {
|
|
3243
|
+
if (Number.isNaN(value)) return "NaN";
|
|
3244
|
+
if (value === Infinity) return "Infinity";
|
|
3245
|
+
if (value === -Infinity) return "-Infinity";
|
|
3246
|
+
return JSON.stringify(value);
|
|
3247
|
+
}
|
|
3248
|
+
return jsonStringifyEnsureAscii(value);
|
|
3249
|
+
}
|
|
3250
|
+
|
|
3251
|
+
function parseYaml(text) {
|
|
3224
3252
|
const raw = String(text || "").trim();
|
|
3225
3253
|
if (!raw) return null;
|
|
3226
3254
|
if (raw.startsWith("{") || raw.startsWith("[")) {
|
|
@@ -4486,44 +4514,44 @@ async function fetchSuggestionsSyncSnapshot({ apiBase, key, timeoutMs, actorScop
|
|
|
4486
4514
|
return body.data || {};
|
|
4487
4515
|
}
|
|
4488
4516
|
|
|
4489
|
-
async function createProjectSuggestions({ apiBase, key, timeoutMs, payload, idempotencyKey, clientSessionId, writeApproval }) {
|
|
4490
|
-
return postSuggestionsMutation({
|
|
4491
|
-
apiBase,
|
|
4492
|
-
key,
|
|
4493
|
-
timeoutMs,
|
|
4494
|
-
endpoint: "/project-assistant/suggestions",
|
|
4495
|
-
payload,
|
|
4496
|
-
idempotencyKey,
|
|
4497
|
-
clientSessionId,
|
|
4498
|
-
writeApproval,
|
|
4499
|
-
});
|
|
4500
|
-
}
|
|
4501
|
-
|
|
4502
|
-
async function reviseProjectSuggestions({ apiBase, key, timeoutMs, payload, idempotencyKey, clientSessionId, writeApproval }) {
|
|
4503
|
-
return postSuggestionsMutation({
|
|
4504
|
-
apiBase,
|
|
4505
|
-
key,
|
|
4506
|
-
timeoutMs,
|
|
4507
|
-
endpoint: "/project-assistant/suggestions/revise",
|
|
4508
|
-
payload,
|
|
4509
|
-
idempotencyKey,
|
|
4510
|
-
clientSessionId,
|
|
4511
|
-
writeApproval,
|
|
4512
|
-
});
|
|
4513
|
-
}
|
|
4514
|
-
|
|
4515
|
-
async function reviewProjectSuggestions({ apiBase, key, timeoutMs, payload, idempotencyKey, clientSessionId, writeApproval }) {
|
|
4516
|
-
return postSuggestionsMutation({
|
|
4517
|
-
apiBase,
|
|
4518
|
-
key,
|
|
4519
|
-
timeoutMs,
|
|
4520
|
-
endpoint: "/project-assistant/suggestions/review",
|
|
4521
|
-
payload,
|
|
4522
|
-
idempotencyKey,
|
|
4523
|
-
clientSessionId,
|
|
4524
|
-
writeApproval,
|
|
4525
|
-
});
|
|
4526
|
-
}
|
|
4517
|
+
async function createProjectSuggestions({ apiBase, key, timeoutMs, payload, idempotencyKey, clientSessionId, writeApproval }) {
|
|
4518
|
+
return postSuggestionsMutation({
|
|
4519
|
+
apiBase,
|
|
4520
|
+
key,
|
|
4521
|
+
timeoutMs,
|
|
4522
|
+
endpoint: "/project-assistant/suggestions",
|
|
4523
|
+
payload,
|
|
4524
|
+
idempotencyKey,
|
|
4525
|
+
clientSessionId,
|
|
4526
|
+
writeApproval,
|
|
4527
|
+
});
|
|
4528
|
+
}
|
|
4529
|
+
|
|
4530
|
+
async function reviseProjectSuggestions({ apiBase, key, timeoutMs, payload, idempotencyKey, clientSessionId, writeApproval }) {
|
|
4531
|
+
return postSuggestionsMutation({
|
|
4532
|
+
apiBase,
|
|
4533
|
+
key,
|
|
4534
|
+
timeoutMs,
|
|
4535
|
+
endpoint: "/project-assistant/suggestions/revise",
|
|
4536
|
+
payload,
|
|
4537
|
+
idempotencyKey,
|
|
4538
|
+
clientSessionId,
|
|
4539
|
+
writeApproval,
|
|
4540
|
+
});
|
|
4541
|
+
}
|
|
4542
|
+
|
|
4543
|
+
async function reviewProjectSuggestions({ apiBase, key, timeoutMs, payload, idempotencyKey, clientSessionId, writeApproval }) {
|
|
4544
|
+
return postSuggestionsMutation({
|
|
4545
|
+
apiBase,
|
|
4546
|
+
key,
|
|
4547
|
+
timeoutMs,
|
|
4548
|
+
endpoint: "/project-assistant/suggestions/review",
|
|
4549
|
+
payload,
|
|
4550
|
+
idempotencyKey,
|
|
4551
|
+
clientSessionId,
|
|
4552
|
+
writeApproval,
|
|
4553
|
+
});
|
|
4554
|
+
}
|
|
4527
4555
|
|
|
4528
4556
|
async function runCreatePrd(args) {
|
|
4529
4557
|
const key = (process.env.MYTE_API_KEY || process.env.MYTE_PROJECT_API_KEY || "").trim();
|
|
@@ -4634,27 +4662,27 @@ async function runCreatePrd(args) {
|
|
|
4634
4662
|
let data;
|
|
4635
4663
|
const payload = payloads[0];
|
|
4636
4664
|
if (clientSessionId) payload.client_session_id = clientSessionId;
|
|
4637
|
-
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
4638
|
-
args,
|
|
4639
|
-
operation: "create_prd",
|
|
4640
|
-
payload,
|
|
4641
|
-
});
|
|
4642
|
-
const writeApproval = requireWriteApproval(args, payload, {
|
|
4643
|
-
operation: "create_prd",
|
|
4644
|
-
artifactKind: "markdown",
|
|
4645
|
-
targets: prdApprovalTargets(payload),
|
|
4646
|
-
});
|
|
4647
|
-
try {
|
|
4648
|
-
data = await postSuggestionsMutation({
|
|
4649
|
-
apiBase,
|
|
4650
|
-
key,
|
|
4651
|
-
payload,
|
|
4665
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
4666
|
+
args,
|
|
4667
|
+
operation: "create_prd",
|
|
4668
|
+
payload,
|
|
4669
|
+
});
|
|
4670
|
+
const writeApproval = requireWriteApproval(args, payload, {
|
|
4671
|
+
operation: "create_prd",
|
|
4672
|
+
artifactKind: "markdown",
|
|
4673
|
+
targets: prdApprovalTargets(payload),
|
|
4674
|
+
});
|
|
4675
|
+
try {
|
|
4676
|
+
data = await postSuggestionsMutation({
|
|
4677
|
+
apiBase,
|
|
4678
|
+
key,
|
|
4679
|
+
payload,
|
|
4652
4680
|
timeoutMs,
|
|
4653
|
-
endpoint: "/project-assistant/create-prd",
|
|
4654
|
-
idempotencyKey,
|
|
4655
|
-
clientSessionId,
|
|
4656
|
-
writeApproval,
|
|
4657
|
-
});
|
|
4681
|
+
endpoint: "/project-assistant/create-prd",
|
|
4682
|
+
idempotencyKey,
|
|
4683
|
+
clientSessionId,
|
|
4684
|
+
writeApproval,
|
|
4685
|
+
});
|
|
4658
4686
|
} catch (err) {
|
|
4659
4687
|
if (err?.name === "AbortError") {
|
|
4660
4688
|
console.error(`Request timed out after ${timeoutMs}ms`);
|
|
@@ -4699,28 +4727,28 @@ async function runCreatePrd(args) {
|
|
|
4699
4727
|
try {
|
|
4700
4728
|
const payload = { items: payloads };
|
|
4701
4729
|
if (clientSessionId) payload.client_session_id = clientSessionId;
|
|
4702
|
-
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
4703
|
-
args,
|
|
4704
|
-
operation: "create_prds",
|
|
4705
|
-
payload,
|
|
4706
|
-
});
|
|
4707
|
-
const prdTargets = prdApprovalTargets(payload);
|
|
4708
|
-
const writeApproval = requireWriteApproval(args, payload, {
|
|
4709
|
-
operation: "create_prds",
|
|
4710
|
-
artifactKind: "markdown",
|
|
4711
|
-
targets: prdTargets,
|
|
4712
|
-
batchCount: prdTargets.length,
|
|
4713
|
-
});
|
|
4714
|
-
const data = await postSuggestionsMutation({
|
|
4715
|
-
apiBase,
|
|
4716
|
-
key,
|
|
4717
|
-
payload,
|
|
4718
|
-
timeoutMs,
|
|
4719
|
-
endpoint: "/project-assistant/create-prds",
|
|
4720
|
-
idempotencyKey,
|
|
4721
|
-
clientSessionId,
|
|
4722
|
-
writeApproval,
|
|
4723
|
-
});
|
|
4730
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
4731
|
+
args,
|
|
4732
|
+
operation: "create_prds",
|
|
4733
|
+
payload,
|
|
4734
|
+
});
|
|
4735
|
+
const prdTargets = prdApprovalTargets(payload);
|
|
4736
|
+
const writeApproval = requireWriteApproval(args, payload, {
|
|
4737
|
+
operation: "create_prds",
|
|
4738
|
+
artifactKind: "markdown",
|
|
4739
|
+
targets: prdTargets,
|
|
4740
|
+
batchCount: prdTargets.length,
|
|
4741
|
+
});
|
|
4742
|
+
const data = await postSuggestionsMutation({
|
|
4743
|
+
apiBase,
|
|
4744
|
+
key,
|
|
4745
|
+
payload,
|
|
4746
|
+
timeoutMs,
|
|
4747
|
+
endpoint: "/project-assistant/create-prds",
|
|
4748
|
+
idempotencyKey,
|
|
4749
|
+
clientSessionId,
|
|
4750
|
+
writeApproval,
|
|
4751
|
+
});
|
|
4724
4752
|
aggregated.project_id = data.project_id || null;
|
|
4725
4753
|
aggregated.created_count = Number(data.created_count || 0);
|
|
4726
4754
|
aggregated.failed_count = Number(data.failed_count || 0);
|
|
@@ -5292,34 +5320,34 @@ async function runFeedbackValidateOrApply(args, mode) {
|
|
|
5292
5320
|
args.client_session_id,
|
|
5293
5321
|
payload.client_session_id
|
|
5294
5322
|
);
|
|
5295
|
-
const idempotencyKey = mode === "apply"
|
|
5296
|
-
? resolveProjectMutationIdempotencyKey({
|
|
5297
|
-
args,
|
|
5298
|
-
operation: `feedback_refinement_apply:${feedbackId}`,
|
|
5299
|
-
payload,
|
|
5300
|
-
})
|
|
5301
|
-
: null;
|
|
5302
|
-
const writeApproval = mode === "apply"
|
|
5303
|
-
? requireWriteApproval(args, payload, {
|
|
5304
|
-
operation: `feedback_refinement_apply:${feedbackId}`,
|
|
5305
|
-
artifactKind: "yaml",
|
|
5306
|
-
targets: [feedbackId],
|
|
5307
|
-
})
|
|
5308
|
-
: null;
|
|
5309
|
-
|
|
5310
|
-
let data;
|
|
5311
|
-
try {
|
|
5312
|
-
data = await postFeedbackRefinement({
|
|
5313
|
-
apiBase,
|
|
5323
|
+
const idempotencyKey = mode === "apply"
|
|
5324
|
+
? resolveProjectMutationIdempotencyKey({
|
|
5325
|
+
args,
|
|
5326
|
+
operation: `feedback_refinement_apply:${feedbackId}`,
|
|
5327
|
+
payload,
|
|
5328
|
+
})
|
|
5329
|
+
: null;
|
|
5330
|
+
const writeApproval = mode === "apply"
|
|
5331
|
+
? requireWriteApproval(args, payload, {
|
|
5332
|
+
operation: `feedback_refinement_apply:${feedbackId}`,
|
|
5333
|
+
artifactKind: "yaml",
|
|
5334
|
+
targets: [feedbackId],
|
|
5335
|
+
})
|
|
5336
|
+
: null;
|
|
5337
|
+
|
|
5338
|
+
let data;
|
|
5339
|
+
try {
|
|
5340
|
+
data = await postFeedbackRefinement({
|
|
5341
|
+
apiBase,
|
|
5314
5342
|
key,
|
|
5315
5343
|
timeoutMs,
|
|
5316
5344
|
feedbackId,
|
|
5317
5345
|
mode,
|
|
5318
|
-
payload,
|
|
5319
|
-
idempotencyKey,
|
|
5320
|
-
clientSessionId,
|
|
5321
|
-
writeApproval,
|
|
5322
|
-
});
|
|
5346
|
+
payload,
|
|
5347
|
+
idempotencyKey,
|
|
5348
|
+
clientSessionId,
|
|
5349
|
+
writeApproval,
|
|
5350
|
+
});
|
|
5323
5351
|
} catch (err) {
|
|
5324
5352
|
if (args.json) {
|
|
5325
5353
|
console.log(JSON.stringify({
|
|
@@ -5364,33 +5392,33 @@ function resolveFeedbackRequestIdArg(args) {
|
|
|
5364
5392
|
return firstNonEmptyString(args["request-id"], args.requestId, args.request_id, args._?.[1]);
|
|
5365
5393
|
}
|
|
5366
5394
|
|
|
5367
|
-
function resolveFeedbackEventIdArg(args) {
|
|
5368
|
-
return firstNonEmptyString(args["event-id"], args.eventId, args.event_id, args._?.[1]);
|
|
5369
|
-
}
|
|
5395
|
+
function resolveFeedbackEventIdArg(args) {
|
|
5396
|
+
return firstNonEmptyString(args["event-id"], args.eventId, args.event_id, args._?.[1]);
|
|
5397
|
+
}
|
|
5370
5398
|
|
|
5371
|
-
function resolveFeedbackVersionIdArg(args) {
|
|
5372
|
-
return firstNonEmptyString(args["version-id"], args.versionId, args.version_id, args._?.[1]);
|
|
5373
|
-
}
|
|
5374
|
-
|
|
5375
|
-
async function resolveFeedbackCommentContent(args, feedbackId) {
|
|
5376
|
-
const explicit = firstNonEmptyString(args.body, args.content, args["body-markdown"], args.bodyMarkdown, args.body_markdown);
|
|
5377
|
-
if (explicit) return explicit;
|
|
5378
|
-
|
|
5379
|
-
const bodyFile = firstNonEmptyString(args["body-file"], args.bodyFile, args.body_file);
|
|
5380
|
-
if (bodyFile) {
|
|
5381
|
-
const bodyPath = resolveInputFile(bodyFile, "Feedback comment body");
|
|
5382
|
-
return fs.readFileSync(bodyPath, "utf8");
|
|
5383
|
-
}
|
|
5384
|
-
|
|
5385
|
-
if (args.stdin) {
|
|
5386
|
-
return readStdinText();
|
|
5387
|
-
}
|
|
5388
|
-
|
|
5389
|
-
const positionals = Array.isArray(args._) ? args._.slice(1) : [];
|
|
5390
|
-
const feedbackIdFromPositional = positionals[0] && String(positionals[0]) === String(feedbackId);
|
|
5391
|
-
const textParts = feedbackIdFromPositional ? positionals.slice(1) : positionals;
|
|
5392
|
-
return textParts.join(" ");
|
|
5393
|
-
}
|
|
5399
|
+
function resolveFeedbackVersionIdArg(args) {
|
|
5400
|
+
return firstNonEmptyString(args["version-id"], args.versionId, args.version_id, args._?.[1]);
|
|
5401
|
+
}
|
|
5402
|
+
|
|
5403
|
+
async function resolveFeedbackCommentContent(args, feedbackId) {
|
|
5404
|
+
const explicit = firstNonEmptyString(args.body, args.content, args["body-markdown"], args.bodyMarkdown, args.body_markdown);
|
|
5405
|
+
if (explicit) return explicit;
|
|
5406
|
+
|
|
5407
|
+
const bodyFile = firstNonEmptyString(args["body-file"], args.bodyFile, args.body_file);
|
|
5408
|
+
if (bodyFile) {
|
|
5409
|
+
const bodyPath = resolveInputFile(bodyFile, "Feedback comment body");
|
|
5410
|
+
return fs.readFileSync(bodyPath, "utf8");
|
|
5411
|
+
}
|
|
5412
|
+
|
|
5413
|
+
if (args.stdin) {
|
|
5414
|
+
return readStdinText();
|
|
5415
|
+
}
|
|
5416
|
+
|
|
5417
|
+
const positionals = Array.isArray(args._) ? args._.slice(1) : [];
|
|
5418
|
+
const feedbackIdFromPositional = positionals[0] && String(positionals[0]) === String(feedbackId);
|
|
5419
|
+
const textParts = feedbackIdFromPositional ? positionals.slice(1) : positionals;
|
|
5420
|
+
return textParts.join(" ");
|
|
5421
|
+
}
|
|
5394
5422
|
|
|
5395
5423
|
function summarizeFeedbackReviewRequestPayload(data) {
|
|
5396
5424
|
const request = data?.request || data || {};
|
|
@@ -5444,29 +5472,29 @@ async function runFeedbackSubmit(args) {
|
|
|
5444
5472
|
args.client_session_id,
|
|
5445
5473
|
payload.client_session_id
|
|
5446
5474
|
);
|
|
5447
|
-
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
5448
|
-
args,
|
|
5449
|
-
operation: `feedback_refinement_request_submit:${feedbackId}`,
|
|
5450
|
-
payload,
|
|
5451
|
-
});
|
|
5452
|
-
const writeApproval = requireWriteApproval(args, payload, {
|
|
5453
|
-
operation: `feedback_refinement_request_submit:${feedbackId}`,
|
|
5454
|
-
artifactKind: "yaml",
|
|
5455
|
-
targets: [feedbackId],
|
|
5456
|
-
});
|
|
5457
|
-
|
|
5458
|
-
let data;
|
|
5459
|
-
try {
|
|
5460
|
-
data = await postFeedbackReviewSubmission({
|
|
5475
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
5476
|
+
args,
|
|
5477
|
+
operation: `feedback_refinement_request_submit:${feedbackId}`,
|
|
5478
|
+
payload,
|
|
5479
|
+
});
|
|
5480
|
+
const writeApproval = requireWriteApproval(args, payload, {
|
|
5481
|
+
operation: `feedback_refinement_request_submit:${feedbackId}`,
|
|
5482
|
+
artifactKind: "yaml",
|
|
5483
|
+
targets: [feedbackId],
|
|
5484
|
+
});
|
|
5485
|
+
|
|
5486
|
+
let data;
|
|
5487
|
+
try {
|
|
5488
|
+
data = await postFeedbackReviewSubmission({
|
|
5461
5489
|
apiBase,
|
|
5462
5490
|
key,
|
|
5463
5491
|
timeoutMs,
|
|
5464
5492
|
feedbackId,
|
|
5465
|
-
payload,
|
|
5466
|
-
idempotencyKey,
|
|
5467
|
-
clientSessionId,
|
|
5468
|
-
writeApproval,
|
|
5469
|
-
});
|
|
5493
|
+
payload,
|
|
5494
|
+
idempotencyKey,
|
|
5495
|
+
clientSessionId,
|
|
5496
|
+
writeApproval,
|
|
5497
|
+
});
|
|
5470
5498
|
} catch (err) {
|
|
5471
5499
|
if (args.json) {
|
|
5472
5500
|
console.log(JSON.stringify({ ok: false, status: err?.status || null, message: err?.message || String(err), data: err?.data || null, artifact_path: absPath }, null, 2));
|
|
@@ -5516,30 +5544,30 @@ async function runFeedbackRevise(args) {
|
|
|
5516
5544
|
args.client_session_id,
|
|
5517
5545
|
payload.client_session_id
|
|
5518
5546
|
);
|
|
5519
|
-
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
5520
|
-
args,
|
|
5521
|
-
operation: `feedback_refinement_request_revise:${requestId}`,
|
|
5522
|
-
payload,
|
|
5523
|
-
});
|
|
5524
|
-
const writeApproval = requireWriteApproval(args, payload, {
|
|
5525
|
-
operation: `feedback_refinement_request_revise:${requestId}`,
|
|
5526
|
-
artifactKind: "yaml",
|
|
5527
|
-
targets: [requestId],
|
|
5528
|
-
});
|
|
5529
|
-
|
|
5530
|
-
let data;
|
|
5531
|
-
try {
|
|
5532
|
-
data = await postFeedbackReviewRequestMutation({
|
|
5547
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
5548
|
+
args,
|
|
5549
|
+
operation: `feedback_refinement_request_revise:${requestId}`,
|
|
5550
|
+
payload,
|
|
5551
|
+
});
|
|
5552
|
+
const writeApproval = requireWriteApproval(args, payload, {
|
|
5553
|
+
operation: `feedback_refinement_request_revise:${requestId}`,
|
|
5554
|
+
artifactKind: "yaml",
|
|
5555
|
+
targets: [requestId],
|
|
5556
|
+
});
|
|
5557
|
+
|
|
5558
|
+
let data;
|
|
5559
|
+
try {
|
|
5560
|
+
data = await postFeedbackReviewRequestMutation({
|
|
5533
5561
|
apiBase,
|
|
5534
5562
|
key,
|
|
5535
5563
|
timeoutMs,
|
|
5536
5564
|
requestId,
|
|
5537
5565
|
endpointAction: "revise",
|
|
5538
|
-
payload,
|
|
5539
|
-
idempotencyKey,
|
|
5540
|
-
clientSessionId,
|
|
5541
|
-
writeApproval,
|
|
5542
|
-
});
|
|
5566
|
+
payload,
|
|
5567
|
+
idempotencyKey,
|
|
5568
|
+
clientSessionId,
|
|
5569
|
+
writeApproval,
|
|
5570
|
+
});
|
|
5543
5571
|
} catch (err) {
|
|
5544
5572
|
if (args.json) {
|
|
5545
5573
|
console.log(JSON.stringify({ ok: false, status: err?.status || null, message: err?.message || String(err), data: err?.data || null, artifact_path: absPath }, null, 2));
|
|
@@ -5665,32 +5693,32 @@ async function runFeedbackReviewDecision(args) {
|
|
|
5665
5693
|
const timeoutMs = resolveTimeoutMs(args);
|
|
5666
5694
|
const apiBase = resolveApiBase(args);
|
|
5667
5695
|
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id, payload.client_session_id);
|
|
5668
|
-
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
5669
|
-
args,
|
|
5670
|
-
operation: `feedback_review_batch:${action}:${items.map((item) => item.request_id || item.id || "").join(",")}`,
|
|
5671
|
-
payload,
|
|
5672
|
-
});
|
|
5673
|
-
const requestTargets = items
|
|
5674
|
-
.map((item, index) => firstNonEmptyString(item.request_id, item.id, item._id) || `index:${index}`)
|
|
5675
|
-
.filter(Boolean);
|
|
5676
|
-
const writeApproval = requireWriteApproval(args, payload, {
|
|
5677
|
-
operation: `feedback_review_batch:${action}`,
|
|
5678
|
-
artifactKind: "yaml",
|
|
5679
|
-
targets: requestTargets,
|
|
5680
|
-
batchCount: items.length,
|
|
5681
|
-
});
|
|
5682
|
-
|
|
5683
|
-
let data;
|
|
5684
|
-
try {
|
|
5685
|
-
data = await postFeedbackBatchReviewMutation({
|
|
5696
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
5697
|
+
args,
|
|
5698
|
+
operation: `feedback_review_batch:${action}:${items.map((item) => item.request_id || item.id || "").join(",")}`,
|
|
5699
|
+
payload,
|
|
5700
|
+
});
|
|
5701
|
+
const requestTargets = items
|
|
5702
|
+
.map((item, index) => firstNonEmptyString(item.request_id, item.id, item._id) || `index:${index}`)
|
|
5703
|
+
.filter(Boolean);
|
|
5704
|
+
const writeApproval = requireWriteApproval(args, payload, {
|
|
5705
|
+
operation: `feedback_review_batch:${action}`,
|
|
5706
|
+
artifactKind: "yaml",
|
|
5707
|
+
targets: requestTargets,
|
|
5708
|
+
batchCount: items.length,
|
|
5709
|
+
});
|
|
5710
|
+
|
|
5711
|
+
let data;
|
|
5712
|
+
try {
|
|
5713
|
+
data = await postFeedbackBatchReviewMutation({
|
|
5686
5714
|
apiBase,
|
|
5687
5715
|
key,
|
|
5688
5716
|
timeoutMs,
|
|
5689
|
-
payload,
|
|
5690
|
-
idempotencyKey,
|
|
5691
|
-
clientSessionId,
|
|
5692
|
-
writeApproval,
|
|
5693
|
-
});
|
|
5717
|
+
payload,
|
|
5718
|
+
idempotencyKey,
|
|
5719
|
+
clientSessionId,
|
|
5720
|
+
writeApproval,
|
|
5721
|
+
});
|
|
5694
5722
|
} catch (err) {
|
|
5695
5723
|
if (args.json) {
|
|
5696
5724
|
console.log(JSON.stringify({ ok: false, status: err?.status || null, message: err?.message || String(err), data: err?.data || null }, null, 2));
|
|
@@ -5734,30 +5762,30 @@ async function runFeedbackReviewDecision(args) {
|
|
|
5734
5762
|
const apiBase = resolveApiBase(args);
|
|
5735
5763
|
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id, payload.client_session_id);
|
|
5736
5764
|
const operationAction = action === "request_changes" ? "request_changes" : action;
|
|
5737
|
-
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
5738
|
-
args,
|
|
5739
|
-
operation: `feedback_review_request_${operationAction}:${requestId}`,
|
|
5740
|
-
payload,
|
|
5741
|
-
});
|
|
5742
|
-
const writeApproval = requireWriteApproval(args, payload, {
|
|
5743
|
-
operation: `feedback_review_request_${operationAction}:${requestId}`,
|
|
5744
|
-
artifactKind: "yaml",
|
|
5745
|
-
targets: [requestId],
|
|
5746
|
-
});
|
|
5747
|
-
|
|
5748
|
-
let data;
|
|
5749
|
-
try {
|
|
5750
|
-
data = await postFeedbackReviewRequestMutation({
|
|
5765
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
5766
|
+
args,
|
|
5767
|
+
operation: `feedback_review_request_${operationAction}:${requestId}`,
|
|
5768
|
+
payload,
|
|
5769
|
+
});
|
|
5770
|
+
const writeApproval = requireWriteApproval(args, payload, {
|
|
5771
|
+
operation: `feedback_review_request_${operationAction}:${requestId}`,
|
|
5772
|
+
artifactKind: "yaml",
|
|
5773
|
+
targets: [requestId],
|
|
5774
|
+
});
|
|
5775
|
+
|
|
5776
|
+
let data;
|
|
5777
|
+
try {
|
|
5778
|
+
data = await postFeedbackReviewRequestMutation({
|
|
5751
5779
|
apiBase,
|
|
5752
5780
|
key,
|
|
5753
5781
|
timeoutMs,
|
|
5754
5782
|
requestId,
|
|
5755
5783
|
endpointAction,
|
|
5756
|
-
payload,
|
|
5757
|
-
idempotencyKey,
|
|
5758
|
-
clientSessionId,
|
|
5759
|
-
writeApproval,
|
|
5760
|
-
});
|
|
5784
|
+
payload,
|
|
5785
|
+
idempotencyKey,
|
|
5786
|
+
clientSessionId,
|
|
5787
|
+
writeApproval,
|
|
5788
|
+
});
|
|
5761
5789
|
} catch (err) {
|
|
5762
5790
|
if (args.json) {
|
|
5763
5791
|
console.log(JSON.stringify({ ok: false, status: err?.status || null, message: err?.message || String(err), data: err?.data || null }, null, 2));
|
|
@@ -5777,7 +5805,7 @@ async function runFeedbackReviewDecision(args) {
|
|
|
5777
5805
|
if (postSync?.error) console.error(`Feedback sync warning: ${postSync.error}`);
|
|
5778
5806
|
}
|
|
5779
5807
|
|
|
5780
|
-
async function runFeedbackMove(args) {
|
|
5808
|
+
async function runFeedbackMove(args) {
|
|
5781
5809
|
const key = getProjectApiKey();
|
|
5782
5810
|
if (!key) {
|
|
5783
5811
|
console.error("Missing MYTE_API_KEY (project key) in environment/.env");
|
|
@@ -5810,28 +5838,28 @@ async function runFeedbackMove(args) {
|
|
|
5810
5838
|
}
|
|
5811
5839
|
const batchId = firstNonEmptyString(args["batch-id"], args.batchId, args.batch_id);
|
|
5812
5840
|
if (batchId) payload.batch_id = batchId;
|
|
5813
|
-
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
5814
|
-
args,
|
|
5815
|
-
operation: `feedback_board_batch_move:${toState}:${feedbackIds.join(",")}`,
|
|
5816
|
-
payload,
|
|
5817
|
-
});
|
|
5818
|
-
const writeApproval = requireWriteApproval(args, payload, {
|
|
5819
|
-
operation: `feedback_board_batch_move:${toState}`,
|
|
5820
|
-
artifactKind: "yaml",
|
|
5821
|
-
targets: feedbackIds,
|
|
5822
|
-
batchCount: feedbackIds.length,
|
|
5823
|
-
});
|
|
5824
|
-
let data;
|
|
5825
|
-
try {
|
|
5826
|
-
data = await postFeedbackBatchBoardMutation({
|
|
5827
|
-
apiBase,
|
|
5828
|
-
key,
|
|
5841
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
5842
|
+
args,
|
|
5843
|
+
operation: `feedback_board_batch_move:${toState}:${feedbackIds.join(",")}`,
|
|
5844
|
+
payload,
|
|
5845
|
+
});
|
|
5846
|
+
const writeApproval = requireWriteApproval(args, payload, {
|
|
5847
|
+
operation: `feedback_board_batch_move:${toState}`,
|
|
5848
|
+
artifactKind: "yaml",
|
|
5849
|
+
targets: feedbackIds,
|
|
5850
|
+
batchCount: feedbackIds.length,
|
|
5851
|
+
});
|
|
5852
|
+
let data;
|
|
5853
|
+
try {
|
|
5854
|
+
data = await postFeedbackBatchBoardMutation({
|
|
5855
|
+
apiBase,
|
|
5856
|
+
key,
|
|
5829
5857
|
timeoutMs,
|
|
5830
|
-
payload,
|
|
5831
|
-
idempotencyKey,
|
|
5832
|
-
clientSessionId,
|
|
5833
|
-
writeApproval,
|
|
5834
|
-
});
|
|
5858
|
+
payload,
|
|
5859
|
+
idempotencyKey,
|
|
5860
|
+
clientSessionId,
|
|
5861
|
+
writeApproval,
|
|
5862
|
+
});
|
|
5835
5863
|
} catch (err) {
|
|
5836
5864
|
if (args.json) {
|
|
5837
5865
|
console.log(JSON.stringify({ ok: false, status: err?.status || null, message: err?.message || String(err), data: err?.data || null }, null, 2));
|
|
@@ -5853,30 +5881,30 @@ async function runFeedbackMove(args) {
|
|
|
5853
5881
|
}
|
|
5854
5882
|
|
|
5855
5883
|
payload.from_state = fromState;
|
|
5856
|
-
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
5857
|
-
args,
|
|
5858
|
-
operation: `feedback_board_move:${feedbackId}`,
|
|
5859
|
-
payload,
|
|
5860
|
-
});
|
|
5861
|
-
const writeApproval = requireWriteApproval(args, payload, {
|
|
5862
|
-
operation: `feedback_board_move:${feedbackId}`,
|
|
5863
|
-
artifactKind: "yaml",
|
|
5864
|
-
targets: [feedbackId],
|
|
5865
|
-
});
|
|
5866
|
-
|
|
5867
|
-
let data;
|
|
5868
|
-
try {
|
|
5869
|
-
data = await postFeedbackBoardMutation({
|
|
5884
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
5885
|
+
args,
|
|
5886
|
+
operation: `feedback_board_move:${feedbackId}`,
|
|
5887
|
+
payload,
|
|
5888
|
+
});
|
|
5889
|
+
const writeApproval = requireWriteApproval(args, payload, {
|
|
5890
|
+
operation: `feedback_board_move:${feedbackId}`,
|
|
5891
|
+
artifactKind: "yaml",
|
|
5892
|
+
targets: [feedbackId],
|
|
5893
|
+
});
|
|
5894
|
+
|
|
5895
|
+
let data;
|
|
5896
|
+
try {
|
|
5897
|
+
data = await postFeedbackBoardMutation({
|
|
5870
5898
|
apiBase,
|
|
5871
5899
|
key,
|
|
5872
5900
|
timeoutMs,
|
|
5873
5901
|
feedbackId,
|
|
5874
5902
|
endpoint: "board-move",
|
|
5875
|
-
payload,
|
|
5876
|
-
idempotencyKey,
|
|
5877
|
-
clientSessionId,
|
|
5878
|
-
writeApproval,
|
|
5879
|
-
});
|
|
5903
|
+
payload,
|
|
5904
|
+
idempotencyKey,
|
|
5905
|
+
clientSessionId,
|
|
5906
|
+
writeApproval,
|
|
5907
|
+
});
|
|
5880
5908
|
} catch (err) {
|
|
5881
5909
|
if (args.json) {
|
|
5882
5910
|
console.log(JSON.stringify({ ok: false, status: err?.status || null, message: err?.message || String(err), data: err?.data || null }, null, 2));
|
|
@@ -5896,92 +5924,92 @@ async function runFeedbackMove(args) {
|
|
|
5896
5924
|
console.log(`State: ${data.feedback_state || toState}`);
|
|
5897
5925
|
if (data.event?.event_id) console.log(`Event: ${data.event.event_id}`);
|
|
5898
5926
|
if (postSync?.error) console.error(`Feedback sync warning: ${postSync.error}`);
|
|
5899
|
-
}
|
|
5900
|
-
|
|
5901
|
-
async function runFeedbackComment(args) {
|
|
5902
|
-
const key = getProjectApiKey();
|
|
5903
|
-
if (!key) {
|
|
5904
|
-
console.error("Missing MYTE_API_KEY (project key) in environment/.env");
|
|
5905
|
-
process.exit(1);
|
|
5906
|
-
}
|
|
5907
|
-
const feedbackId = resolveFeedbackIdArg(args);
|
|
5908
|
-
if (!feedbackId) {
|
|
5909
|
-
console.error("Missing --feedback-id.");
|
|
5910
|
-
process.exit(1);
|
|
5911
|
-
}
|
|
5912
|
-
|
|
5913
|
-
const content = String(await resolveFeedbackCommentContent(args, feedbackId) || "").trim();
|
|
5914
|
-
if (!content) {
|
|
5915
|
-
console.error("Missing feedback comment body. Use --body, --body-file, --stdin, or positional text.");
|
|
5916
|
-
process.exit(1);
|
|
5917
|
-
}
|
|
5918
|
-
|
|
5919
|
-
const payload = { content };
|
|
5920
|
-
const timeoutMs = resolveTimeoutMs(args);
|
|
5921
|
-
const apiBase = resolveApiBase(args);
|
|
5922
|
-
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id);
|
|
5923
|
-
if (clientSessionId) payload.client_session_id = clientSessionId;
|
|
5924
|
-
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
5925
|
-
args,
|
|
5926
|
-
operation: `feedback_comment_create:${feedbackId}`,
|
|
5927
|
-
payload,
|
|
5928
|
-
});
|
|
5929
|
-
|
|
5930
|
-
if (args["print-context"] || args.printContext || args["dry-run"] || args.dryRun) {
|
|
5931
|
-
console.log(JSON.stringify(payload, null, 2));
|
|
5932
|
-
return;
|
|
5933
|
-
}
|
|
5934
|
-
|
|
5935
|
-
const writeApproval = requireWriteApproval(args, payload, {
|
|
5936
|
-
operation: `feedback_comment_create:${feedbackId}`,
|
|
5937
|
-
artifactKind: "markdown",
|
|
5938
|
-
targets: [feedbackId],
|
|
5939
|
-
});
|
|
5940
|
-
|
|
5941
|
-
let data;
|
|
5942
|
-
try {
|
|
5943
|
-
data = await postFeedbackComment({
|
|
5944
|
-
apiBase,
|
|
5945
|
-
key,
|
|
5946
|
-
timeoutMs,
|
|
5947
|
-
feedbackId,
|
|
5948
|
-
payload,
|
|
5949
|
-
idempotencyKey,
|
|
5950
|
-
clientSessionId,
|
|
5951
|
-
writeApproval,
|
|
5952
|
-
});
|
|
5953
|
-
} catch (err) {
|
|
5954
|
-
if (args.json) {
|
|
5955
|
-
console.log(JSON.stringify({ ok: false, status: err?.status || null, message: err?.message || String(err), data: err?.data || null }, null, 2));
|
|
5956
|
-
} else {
|
|
5957
|
-
console.error("Feedback comment failed:", err?.message || err);
|
|
5958
|
-
if (err?.data) console.error(JSON.stringify(err.data, null, 2));
|
|
5959
|
-
}
|
|
5960
|
-
process.exit(1);
|
|
5961
|
-
}
|
|
5962
|
-
|
|
5963
|
-
const postSync = await refreshFeedbackSnapshotAfterMutation(args, { apiBase, key, timeoutMs });
|
|
5964
|
-
if (args.json) {
|
|
5965
|
-
console.log(JSON.stringify({ ok: true, ...data, post_sync: postSync }, null, 2));
|
|
5966
|
-
return;
|
|
5967
|
-
}
|
|
5968
|
-
|
|
5969
|
-
if (data.comment_id) console.log(`Comment ID: ${data.comment_id}`);
|
|
5970
|
-
console.log(`Feedback: ${data.feedback_id || feedbackId}`);
|
|
5971
|
-
if (data.project_id) console.log(`Project ID: ${data.project_id}`);
|
|
5972
|
-
if (data.user_name) console.log(`Author: ${data.user_name}`);
|
|
5973
|
-
if (data.created_at) console.log(`Created At: ${data.created_at}`);
|
|
5974
|
-
if (data.content) {
|
|
5975
|
-
const body = String(data.content);
|
|
5976
|
-
const truncated = body.length > 2000 ? `${body.slice(0, 2000)}\n...[truncated]` : body;
|
|
5977
|
-
console.log("Content:");
|
|
5978
|
-
console.log(truncated);
|
|
5979
|
-
}
|
|
5980
|
-
if (postSync?.data_root) console.log(`Synced feedback: ${postSync.data_root}`);
|
|
5981
|
-
if (postSync?.error) console.error(`Feedback sync warning: ${postSync.error}`);
|
|
5982
|
-
}
|
|
5983
|
-
|
|
5984
|
-
async function runFeedbackUndo(args) {
|
|
5927
|
+
}
|
|
5928
|
+
|
|
5929
|
+
async function runFeedbackComment(args) {
|
|
5930
|
+
const key = getProjectApiKey();
|
|
5931
|
+
if (!key) {
|
|
5932
|
+
console.error("Missing MYTE_API_KEY (project key) in environment/.env");
|
|
5933
|
+
process.exit(1);
|
|
5934
|
+
}
|
|
5935
|
+
const feedbackId = resolveFeedbackIdArg(args);
|
|
5936
|
+
if (!feedbackId) {
|
|
5937
|
+
console.error("Missing --feedback-id.");
|
|
5938
|
+
process.exit(1);
|
|
5939
|
+
}
|
|
5940
|
+
|
|
5941
|
+
const content = String(await resolveFeedbackCommentContent(args, feedbackId) || "").trim();
|
|
5942
|
+
if (!content) {
|
|
5943
|
+
console.error("Missing feedback comment body. Use --body, --body-file, --stdin, or positional text.");
|
|
5944
|
+
process.exit(1);
|
|
5945
|
+
}
|
|
5946
|
+
|
|
5947
|
+
const payload = { content };
|
|
5948
|
+
const timeoutMs = resolveTimeoutMs(args);
|
|
5949
|
+
const apiBase = resolveApiBase(args);
|
|
5950
|
+
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id);
|
|
5951
|
+
if (clientSessionId) payload.client_session_id = clientSessionId;
|
|
5952
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
5953
|
+
args,
|
|
5954
|
+
operation: `feedback_comment_create:${feedbackId}`,
|
|
5955
|
+
payload,
|
|
5956
|
+
});
|
|
5957
|
+
|
|
5958
|
+
if (args["print-context"] || args.printContext || args["dry-run"] || args.dryRun) {
|
|
5959
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
5960
|
+
return;
|
|
5961
|
+
}
|
|
5962
|
+
|
|
5963
|
+
const writeApproval = requireWriteApproval(args, payload, {
|
|
5964
|
+
operation: `feedback_comment_create:${feedbackId}`,
|
|
5965
|
+
artifactKind: "markdown",
|
|
5966
|
+
targets: [feedbackId],
|
|
5967
|
+
});
|
|
5968
|
+
|
|
5969
|
+
let data;
|
|
5970
|
+
try {
|
|
5971
|
+
data = await postFeedbackComment({
|
|
5972
|
+
apiBase,
|
|
5973
|
+
key,
|
|
5974
|
+
timeoutMs,
|
|
5975
|
+
feedbackId,
|
|
5976
|
+
payload,
|
|
5977
|
+
idempotencyKey,
|
|
5978
|
+
clientSessionId,
|
|
5979
|
+
writeApproval,
|
|
5980
|
+
});
|
|
5981
|
+
} catch (err) {
|
|
5982
|
+
if (args.json) {
|
|
5983
|
+
console.log(JSON.stringify({ ok: false, status: err?.status || null, message: err?.message || String(err), data: err?.data || null }, null, 2));
|
|
5984
|
+
} else {
|
|
5985
|
+
console.error("Feedback comment failed:", err?.message || err);
|
|
5986
|
+
if (err?.data) console.error(JSON.stringify(err.data, null, 2));
|
|
5987
|
+
}
|
|
5988
|
+
process.exit(1);
|
|
5989
|
+
}
|
|
5990
|
+
|
|
5991
|
+
const postSync = await refreshFeedbackSnapshotAfterMutation(args, { apiBase, key, timeoutMs });
|
|
5992
|
+
if (args.json) {
|
|
5993
|
+
console.log(JSON.stringify({ ok: true, ...data, post_sync: postSync }, null, 2));
|
|
5994
|
+
return;
|
|
5995
|
+
}
|
|
5996
|
+
|
|
5997
|
+
if (data.comment_id) console.log(`Comment ID: ${data.comment_id}`);
|
|
5998
|
+
console.log(`Feedback: ${data.feedback_id || feedbackId}`);
|
|
5999
|
+
if (data.project_id) console.log(`Project ID: ${data.project_id}`);
|
|
6000
|
+
if (data.user_name) console.log(`Author: ${data.user_name}`);
|
|
6001
|
+
if (data.created_at) console.log(`Created At: ${data.created_at}`);
|
|
6002
|
+
if (data.content) {
|
|
6003
|
+
const body = String(data.content);
|
|
6004
|
+
const truncated = body.length > 2000 ? `${body.slice(0, 2000)}\n...[truncated]` : body;
|
|
6005
|
+
console.log("Content:");
|
|
6006
|
+
console.log(truncated);
|
|
6007
|
+
}
|
|
6008
|
+
if (postSync?.data_root) console.log(`Synced feedback: ${postSync.data_root}`);
|
|
6009
|
+
if (postSync?.error) console.error(`Feedback sync warning: ${postSync.error}`);
|
|
6010
|
+
}
|
|
6011
|
+
|
|
6012
|
+
async function runFeedbackUndo(args) {
|
|
5985
6013
|
const key = getProjectApiKey();
|
|
5986
6014
|
if (!key) {
|
|
5987
6015
|
console.error("Missing MYTE_API_KEY (project key) in environment/.env");
|
|
@@ -6001,36 +6029,36 @@ async function runFeedbackUndo(args) {
|
|
|
6001
6029
|
const timeoutMs = resolveTimeoutMs(args);
|
|
6002
6030
|
const apiBase = resolveApiBase(args);
|
|
6003
6031
|
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id);
|
|
6004
|
-
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
6005
|
-
args,
|
|
6006
|
-
operation: `feedback_event_undo:${feedbackId}:${eventId}`,
|
|
6007
|
-
payload,
|
|
6008
|
-
});
|
|
6009
|
-
|
|
6010
|
-
if (args["print-context"] || args.printContext || args["dry-run"] || args.dryRun) {
|
|
6011
|
-
console.log(JSON.stringify(payload, null, 2));
|
|
6012
|
-
return;
|
|
6013
|
-
}
|
|
6014
|
-
|
|
6015
|
-
const writeApproval = requireWriteApproval(args, payload, {
|
|
6016
|
-
operation: `feedback_event_undo:${feedbackId}:${eventId}`,
|
|
6017
|
-
artifactKind: "yaml",
|
|
6018
|
-
targets: [feedbackId, eventId],
|
|
6019
|
-
});
|
|
6020
|
-
|
|
6021
|
-
let data;
|
|
6022
|
-
try {
|
|
6032
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
6033
|
+
args,
|
|
6034
|
+
operation: `feedback_event_undo:${feedbackId}:${eventId}`,
|
|
6035
|
+
payload,
|
|
6036
|
+
});
|
|
6037
|
+
|
|
6038
|
+
if (args["print-context"] || args.printContext || args["dry-run"] || args.dryRun) {
|
|
6039
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
6040
|
+
return;
|
|
6041
|
+
}
|
|
6042
|
+
|
|
6043
|
+
const writeApproval = requireWriteApproval(args, payload, {
|
|
6044
|
+
operation: `feedback_event_undo:${feedbackId}:${eventId}`,
|
|
6045
|
+
artifactKind: "yaml",
|
|
6046
|
+
targets: [feedbackId, eventId],
|
|
6047
|
+
});
|
|
6048
|
+
|
|
6049
|
+
let data;
|
|
6050
|
+
try {
|
|
6023
6051
|
data = await postFeedbackBoardMutation({
|
|
6024
6052
|
apiBase,
|
|
6025
6053
|
key,
|
|
6026
6054
|
timeoutMs,
|
|
6027
6055
|
feedbackId,
|
|
6028
6056
|
endpoint: `events/${encodeURIComponent(String(eventId))}/undo`,
|
|
6029
|
-
payload,
|
|
6030
|
-
idempotencyKey,
|
|
6031
|
-
clientSessionId,
|
|
6032
|
-
writeApproval,
|
|
6033
|
-
});
|
|
6057
|
+
payload,
|
|
6058
|
+
idempotencyKey,
|
|
6059
|
+
clientSessionId,
|
|
6060
|
+
writeApproval,
|
|
6061
|
+
});
|
|
6034
6062
|
} catch (err) {
|
|
6035
6063
|
if (args.json) {
|
|
6036
6064
|
console.log(JSON.stringify({ ok: false, status: err?.status || null, message: err?.message || String(err), data: err?.data || null }, null, 2));
|
|
@@ -6188,15 +6216,15 @@ async function runFeedback(args) {
|
|
|
6188
6216
|
await runFeedbackReviewDecision(args);
|
|
6189
6217
|
return;
|
|
6190
6218
|
}
|
|
6191
|
-
if (subcommand === "move") {
|
|
6192
|
-
await runFeedbackMove(args);
|
|
6193
|
-
return;
|
|
6194
|
-
}
|
|
6195
|
-
if (subcommand === "comment" || subcommand === "comments") {
|
|
6196
|
-
await runFeedbackComment(args);
|
|
6197
|
-
return;
|
|
6198
|
-
}
|
|
6199
|
-
if (subcommand === "undo") {
|
|
6219
|
+
if (subcommand === "move") {
|
|
6220
|
+
await runFeedbackMove(args);
|
|
6221
|
+
return;
|
|
6222
|
+
}
|
|
6223
|
+
if (subcommand === "comment" || subcommand === "comments") {
|
|
6224
|
+
await runFeedbackComment(args);
|
|
6225
|
+
return;
|
|
6226
|
+
}
|
|
6227
|
+
if (subcommand === "undo") {
|
|
6200
6228
|
await runFeedbackUndo(args);
|
|
6201
6229
|
return;
|
|
6202
6230
|
}
|
|
@@ -6212,7 +6240,7 @@ async function runFeedback(args) {
|
|
|
6212
6240
|
await runFeedbackGetOrHistory(args, subcommand);
|
|
6213
6241
|
return;
|
|
6214
6242
|
}
|
|
6215
|
-
console.error("Unknown feedback command. Use status, edit, assign, archive, submit, revise, reviews, review, move, comment, undo, prd-versions, prd-diff, get, history, validate, or apply.");
|
|
6243
|
+
console.error("Unknown feedback command. Use status, edit, assign, archive, submit, revise, reviews, review, move, comment, undo, prd-versions, prd-diff, get, history, validate, or apply.");
|
|
6216
6244
|
process.exit(1);
|
|
6217
6245
|
}
|
|
6218
6246
|
|
|
@@ -6403,30 +6431,30 @@ async function runSuggestionsCreate(args) {
|
|
|
6403
6431
|
process.exit(1);
|
|
6404
6432
|
}
|
|
6405
6433
|
|
|
6406
|
-
if (args["print-context"] || args.printContext || args["dry-run"] || args.dryRun) {
|
|
6407
|
-
console.log(JSON.stringify(context.payload, null, 2));
|
|
6408
|
-
return;
|
|
6409
|
-
}
|
|
6410
|
-
|
|
6411
|
-
const createTargets = suggestionApprovalTargets(context.payload);
|
|
6412
|
-
const writeApproval = requireWriteApproval(args, context.payload, {
|
|
6413
|
-
operation: "suggestions.create",
|
|
6414
|
-
artifactKind: "yaml",
|
|
6415
|
-
targets: createTargets,
|
|
6416
|
-
batchCount: createTargets.length > 1 ? createTargets.length : null,
|
|
6417
|
-
});
|
|
6418
|
-
|
|
6419
|
-
let data;
|
|
6420
|
-
try {
|
|
6421
|
-
data = await createProjectSuggestions({
|
|
6422
|
-
apiBase: context.apiBase,
|
|
6423
|
-
key: context.key,
|
|
6434
|
+
if (args["print-context"] || args.printContext || args["dry-run"] || args.dryRun) {
|
|
6435
|
+
console.log(JSON.stringify(context.payload, null, 2));
|
|
6436
|
+
return;
|
|
6437
|
+
}
|
|
6438
|
+
|
|
6439
|
+
const createTargets = suggestionApprovalTargets(context.payload);
|
|
6440
|
+
const writeApproval = requireWriteApproval(args, context.payload, {
|
|
6441
|
+
operation: "suggestions.create",
|
|
6442
|
+
artifactKind: "yaml",
|
|
6443
|
+
targets: createTargets,
|
|
6444
|
+
batchCount: createTargets.length > 1 ? createTargets.length : null,
|
|
6445
|
+
});
|
|
6446
|
+
|
|
6447
|
+
let data;
|
|
6448
|
+
try {
|
|
6449
|
+
data = await createProjectSuggestions({
|
|
6450
|
+
apiBase: context.apiBase,
|
|
6451
|
+
key: context.key,
|
|
6424
6452
|
timeoutMs: context.timeoutMs,
|
|
6425
|
-
payload: context.payload,
|
|
6426
|
-
idempotencyKey: context.idempotencyKey,
|
|
6427
|
-
clientSessionId: context.clientSessionId,
|
|
6428
|
-
writeApproval,
|
|
6429
|
-
});
|
|
6453
|
+
payload: context.payload,
|
|
6454
|
+
idempotencyKey: context.idempotencyKey,
|
|
6455
|
+
clientSessionId: context.clientSessionId,
|
|
6456
|
+
writeApproval,
|
|
6457
|
+
});
|
|
6430
6458
|
} catch (err) {
|
|
6431
6459
|
console.error("Suggestions create failed:", err?.message || err);
|
|
6432
6460
|
process.exit(1);
|
|
@@ -6497,30 +6525,30 @@ async function runSuggestionsRevise(args) {
|
|
|
6497
6525
|
process.exit(1);
|
|
6498
6526
|
}
|
|
6499
6527
|
|
|
6500
|
-
if (args["print-context"] || args.printContext || args["dry-run"] || args.dryRun) {
|
|
6501
|
-
console.log(JSON.stringify(context.payload, null, 2));
|
|
6502
|
-
return;
|
|
6503
|
-
}
|
|
6504
|
-
|
|
6505
|
-
const reviseTargets = suggestionApprovalTargets(context.payload);
|
|
6506
|
-
const writeApproval = requireWriteApproval(args, context.payload, {
|
|
6507
|
-
operation: "suggestions.revise",
|
|
6508
|
-
artifactKind: "yaml",
|
|
6509
|
-
targets: reviseTargets,
|
|
6510
|
-
batchCount: reviseTargets.length > 1 ? reviseTargets.length : null,
|
|
6511
|
-
});
|
|
6512
|
-
|
|
6513
|
-
let data;
|
|
6514
|
-
try {
|
|
6515
|
-
data = await reviseProjectSuggestions({
|
|
6516
|
-
apiBase: context.apiBase,
|
|
6517
|
-
key: context.key,
|
|
6528
|
+
if (args["print-context"] || args.printContext || args["dry-run"] || args.dryRun) {
|
|
6529
|
+
console.log(JSON.stringify(context.payload, null, 2));
|
|
6530
|
+
return;
|
|
6531
|
+
}
|
|
6532
|
+
|
|
6533
|
+
const reviseTargets = suggestionApprovalTargets(context.payload);
|
|
6534
|
+
const writeApproval = requireWriteApproval(args, context.payload, {
|
|
6535
|
+
operation: "suggestions.revise",
|
|
6536
|
+
artifactKind: "yaml",
|
|
6537
|
+
targets: reviseTargets,
|
|
6538
|
+
batchCount: reviseTargets.length > 1 ? reviseTargets.length : null,
|
|
6539
|
+
});
|
|
6540
|
+
|
|
6541
|
+
let data;
|
|
6542
|
+
try {
|
|
6543
|
+
data = await reviseProjectSuggestions({
|
|
6544
|
+
apiBase: context.apiBase,
|
|
6545
|
+
key: context.key,
|
|
6518
6546
|
timeoutMs: context.timeoutMs,
|
|
6519
|
-
payload: context.payload,
|
|
6520
|
-
idempotencyKey: context.idempotencyKey,
|
|
6521
|
-
clientSessionId: context.clientSessionId,
|
|
6522
|
-
writeApproval,
|
|
6523
|
-
});
|
|
6547
|
+
payload: context.payload,
|
|
6548
|
+
idempotencyKey: context.idempotencyKey,
|
|
6549
|
+
clientSessionId: context.clientSessionId,
|
|
6550
|
+
writeApproval,
|
|
6551
|
+
});
|
|
6524
6552
|
} catch (err) {
|
|
6525
6553
|
console.error("Suggestions revise failed:", err?.message || err);
|
|
6526
6554
|
process.exit(1);
|
|
@@ -6589,30 +6617,30 @@ async function runSuggestionsReview(args) {
|
|
|
6589
6617
|
process.exit(1);
|
|
6590
6618
|
}
|
|
6591
6619
|
|
|
6592
|
-
if (args["print-context"] || args.printContext || args["dry-run"] || args.dryRun) {
|
|
6593
|
-
console.log(JSON.stringify(context.payload, null, 2));
|
|
6594
|
-
return;
|
|
6595
|
-
}
|
|
6596
|
-
|
|
6597
|
-
const reviewTargets = suggestionApprovalTargets(context.payload);
|
|
6598
|
-
const writeApproval = requireWriteApproval(args, context.payload, {
|
|
6599
|
-
operation: "suggestions.review",
|
|
6600
|
-
artifactKind: "yaml",
|
|
6601
|
-
targets: reviewTargets,
|
|
6602
|
-
batchCount: reviewTargets.length > 1 ? reviewTargets.length : null,
|
|
6603
|
-
});
|
|
6604
|
-
|
|
6605
|
-
let data;
|
|
6606
|
-
try {
|
|
6607
|
-
data = await reviewProjectSuggestions({
|
|
6608
|
-
apiBase: context.apiBase,
|
|
6609
|
-
key: context.key,
|
|
6620
|
+
if (args["print-context"] || args.printContext || args["dry-run"] || args.dryRun) {
|
|
6621
|
+
console.log(JSON.stringify(context.payload, null, 2));
|
|
6622
|
+
return;
|
|
6623
|
+
}
|
|
6624
|
+
|
|
6625
|
+
const reviewTargets = suggestionApprovalTargets(context.payload);
|
|
6626
|
+
const writeApproval = requireWriteApproval(args, context.payload, {
|
|
6627
|
+
operation: "suggestions.review",
|
|
6628
|
+
artifactKind: "yaml",
|
|
6629
|
+
targets: reviewTargets,
|
|
6630
|
+
batchCount: reviewTargets.length > 1 ? reviewTargets.length : null,
|
|
6631
|
+
});
|
|
6632
|
+
|
|
6633
|
+
let data;
|
|
6634
|
+
try {
|
|
6635
|
+
data = await reviewProjectSuggestions({
|
|
6636
|
+
apiBase: context.apiBase,
|
|
6637
|
+
key: context.key,
|
|
6610
6638
|
timeoutMs: context.timeoutMs,
|
|
6611
|
-
payload: context.payload,
|
|
6612
|
-
idempotencyKey: context.idempotencyKey,
|
|
6613
|
-
clientSessionId: context.clientSessionId,
|
|
6614
|
-
writeApproval,
|
|
6615
|
-
});
|
|
6639
|
+
payload: context.payload,
|
|
6640
|
+
idempotencyKey: context.idempotencyKey,
|
|
6641
|
+
clientSessionId: context.clientSessionId,
|
|
6642
|
+
writeApproval,
|
|
6643
|
+
});
|
|
6616
6644
|
} catch (err) {
|
|
6617
6645
|
console.error("Suggestions review failed:", err?.message || err);
|
|
6618
6646
|
process.exit(1);
|