@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/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(stableJsonStringify(canonicalizeWritePayload(payload || {})))
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 parseYaml(text) {
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);