@mytegroupinc/myte-core 0.0.45 → 0.0.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -48
- package/THIRD_PARTY_NOTICES.md +21 -21
- package/TRADEMARKS.md +10 -10
- package/cli.js +505 -570
- package/lib/mytecody-release-public-key.pem +11 -11
- package/lib/mytecody-splash.js +251 -251
- package/mytecody-cli.js +2025 -2025
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -26,9 +26,9 @@ const DEFAULT_DIFF_LIMIT_CHARS = 500_000;
|
|
|
26
26
|
const REMOVED_COMMAND_MESSAGES = {
|
|
27
27
|
ask: "The `ask` alias has been removed. Use `myte query \"...\"`.",
|
|
28
28
|
chat: "The `chat` command has been removed. Use repeated `myte query` calls instead.",
|
|
29
|
-
"create-prds": "The `create-prds` alias has been removed. Use `myte create-prd <file.md> [more.md ...]
|
|
30
|
-
"add-prd": "The `add-prd` alias has been removed. Use `myte create-prd <file.md> [more.md ...]
|
|
31
|
-
prd: "The `prd` alias has been removed. Use `myte create-prd <file.md> [more.md ...]
|
|
29
|
+
"create-prds": "The `create-prds` alias has been removed. Use `myte create-prd <file.md> [more.md ...] --confirm-write --approval-artifact <path>`.",
|
|
30
|
+
"add-prd": "The `add-prd` alias has been removed. Use `myte create-prd <file.md> [more.md ...] --confirm-write --approval-artifact <path>`.",
|
|
31
|
+
prd: "The `prd` alias has been removed. Use `myte create-prd <file.md> [more.md ...] --confirm-write --approval-artifact <path>`.",
|
|
32
32
|
"qaqc-status-update": "The `qaqc-status-update` command has been removed. Use `myte mission status --mission-ids \"M001,M002\" --status todo|in_progress|done`.",
|
|
33
33
|
"mission-restore": "The project-key `myte mission restore` command has been removed. Restore archived missions from the Myte web archived missions board.",
|
|
34
34
|
};
|
|
@@ -190,12 +190,12 @@ function printHelp() {
|
|
|
190
190
|
" myte mission archive --mission-ids \"M001[,M002...]\" [--reason \"...\"] [--no-sync] [--json]",
|
|
191
191
|
" myte sync-qaqc [--output-dir ./MyteCommandCenter] [--json]",
|
|
192
192
|
" myte suggestions sync [--output-dir ./MyteCommandCenter] [--json]",
|
|
193
|
-
" myte suggestions create [--file ./payload.yml] [--no-sync] [--json]",
|
|
194
|
-
" myte suggestions revise [--file ./payload.yml] [--no-sync] [--json]",
|
|
195
|
-
" myte suggestions review [--file ./payload.yml] [--no-sync] [--json]",
|
|
196
|
-
" myte update-team \"<content>\" [--json]",
|
|
197
|
-
" myte update-owner --subject \"<text>\" [--body-markdown \"...\"] [--body-file ./update.md] [--json]",
|
|
198
|
-
" myte update-client --subject \"<text>\" [--body-markdown \"...\"] [--body-file ./update.md] [--target-contact-ids <id1,id2>] [--json]",
|
|
193
|
+
" myte suggestions create [--file ./payload.yml] --confirm-write --approval-artifact <path> [--no-sync] [--json]",
|
|
194
|
+
" myte suggestions revise [--file ./payload.yml] --confirm-write --approval-artifact <path> [--no-sync] [--json]",
|
|
195
|
+
" myte suggestions review [--file ./payload.yml] [--no-sync] [--json]",
|
|
196
|
+
" myte update-team \"<content>\" --confirm-write --approval-artifact <path> [--json]",
|
|
197
|
+
" myte update-owner --subject \"<text>\" [--body-markdown \"...\"] [--body-file ./update.md] --confirm-write --approval-artifact <path> [--json]",
|
|
198
|
+
" myte update-client --subject \"<text>\" [--body-markdown \"...\"] [--body-file ./update.md] [--target-contact-ids <id1,id2>] --confirm-write --approval-artifact <path> [--json]",
|
|
199
199
|
" myte feedback-sync [--status <value>] [--source <value>] [--with-prd-text|--no-with-prd-text] [--output-dir ./MyteCommandCenter] [--json]",
|
|
200
200
|
" myte feedback get --feedback-id <id> [--json]",
|
|
201
201
|
" myte feedback history --feedback-id <id> [--limit 50] [--json]",
|
|
@@ -203,23 +203,23 @@ function printHelp() {
|
|
|
203
203
|
" myte feedback edit --feedback-id <id> [--title \"...\"] [--feedback-text \"...\"] [--priority High] [--reason \"...\"]",
|
|
204
204
|
" myte feedback assign --feedback-id <id> --user-id <id> [--reason \"...\"]",
|
|
205
205
|
" myte feedback archive --feedback-id <id> --reason \"...\"",
|
|
206
|
-
" myte feedback submit --file ./MyteCommandCenter/reviews/feedback/<id>-edit.yml [--json]",
|
|
207
|
-
" myte feedback revise --request-id <id> --file ./MyteCommandCenter/reviews/feedback/<id>-edit.yml [--json]",
|
|
206
|
+
" myte feedback submit --file ./MyteCommandCenter/reviews/feedback/<id>-edit.yml --confirm-write --approval-artifact <path> [--json]",
|
|
207
|
+
" myte feedback revise --request-id <id> --file ./MyteCommandCenter/reviews/feedback/<id>-edit.yml --confirm-write --approval-artifact <path> [--json]",
|
|
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
211
|
" myte feedback move --feedback-id <id> --to-state in_progress --from-state todo --reason \"...\" [--json]",
|
|
212
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]",
|
|
213
|
+
" myte feedback comment --feedback-id <id> --body \"...\" [--body-file ./comment.md] --confirm-write --approval-artifact <path> [--json]",
|
|
214
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]",
|
|
218
218
|
" myte feedback apply --file ./MyteCommandCenter/reviews/feedback/<id>-status.yml [--json]",
|
|
219
|
-
" myte create-prd <file.md> [more.md ...] [--json] [--title \"...\"] [--description \"...\"]",
|
|
220
|
-
" cat file.md | myte create-prd --stdin [--title \"...\"] [--description \"...\"]",
|
|
221
|
-
" cat update.md | myte update-owner --stdin --subject \"Owner update\"",
|
|
222
|
-
" cat update.md | myte update-client --stdin --subject \"Weekly client update\"",
|
|
219
|
+
" myte create-prd <file.md> [more.md ...] --confirm-write --approval-artifact <path> [--json] [--title \"...\"] [--description \"...\"]",
|
|
220
|
+
" cat file.md | myte create-prd --stdin --confirm-write --approval-artifact <path> [--title \"...\"] [--description \"...\"]",
|
|
221
|
+
" cat update.md | myte update-owner --stdin --subject \"Owner update\" --confirm-write --approval-artifact ./update.md",
|
|
222
|
+
" cat update.md | myte update-client --stdin --subject \"Weekly client update\" --confirm-write --approval-artifact ./update.md",
|
|
223
223
|
"",
|
|
224
224
|
"Run forms:",
|
|
225
225
|
" npm install myte then npx myte query \"...\" --with-diff",
|
|
@@ -235,12 +235,6 @@ function printHelp() {
|
|
|
235
235
|
" - Set MYTE_API_KEY in a workspace .env (or env var)",
|
|
236
236
|
" - Set MYTEAI_API_KEY in a workspace .env (or env var) for `myte ai`",
|
|
237
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
238
|
"bootstrap contract:",
|
|
245
239
|
" - Run from any workspace where you want local MyteCommandCenter data written",
|
|
246
240
|
" - Writes MyteCommandCenter/data/project.yml plus phases, epics, stories, and missions locally",
|
|
@@ -334,11 +328,23 @@ function printHelp() {
|
|
|
334
328
|
" - project-key API/CLI cannot unarchive archived Feedback; use the web archived Feedback view",
|
|
335
329
|
" - get/history read current feedback snapshots and audited event history through the project-key API",
|
|
336
330
|
" - prd-versions/prd-diff expose retained PRD versions and backend-generated text diffs",
|
|
337
|
-
" - validate/apply send artifacts to /api/project-assistant/feedback/<id>/refinement/* for validation or owner-direct apply",
|
|
338
|
-
" - The backend owns authorization, stale snapshot checks, allowed field/transition rules, and history",
|
|
339
|
-
" - apply is idempotent and does not rewrite local feedback.yml; run feedback-sync after apply to refresh local state",
|
|
340
|
-
"",
|
|
341
|
-
"
|
|
331
|
+
" - validate/apply send artifacts to /api/project-assistant/feedback/<id>/refinement/* for validation or owner-direct apply",
|
|
332
|
+
" - The backend owns authorization, stale snapshot checks, allowed field/transition rules, and history",
|
|
333
|
+
" - apply is idempotent and does not rewrite local feedback.yml; run feedback-sync after apply to refresh local state",
|
|
334
|
+
"",
|
|
335
|
+
"approval artifact requirements:",
|
|
336
|
+
" - Required: create-prd, update-team, update-owner, update-client, feedback submit/revise/comment, suggestions create/revise",
|
|
337
|
+
" - Not required: run-qaqc, mission status/archive, suggestions review, feedback review/move/undo/apply",
|
|
338
|
+
" - Never required: read/sync/query/validate commands, --print-context, --dry-run, and feedback local draft commands",
|
|
339
|
+
" - For required actions, prepare a .md/.markdown/.yml/.yaml/.json artifact, show it to the user, then rerun with --confirm-write --approval-artifact <path>",
|
|
340
|
+
" - In plain language, the artifact is the human-reviewed record of the exact write the agent is about to send; it is not a permission grant and does not bypass owner/delegate checks, idempotency, stale-state guards, validation, or audit",
|
|
341
|
+
" - Minimum artifact contents: exact command; every target id or PRD item; complete proposed-change summary; reason/approval note; batch_count when one command sends multiple items",
|
|
342
|
+
" - Mission edit/create batches use suggestions create/revise and must enumerate each item: update items include change_type: update, mission_id, and changed fields; create items include change_type: create, title, description, and acceptance details; revisions include suggestion_id and expected_revision",
|
|
343
|
+
" - PRD batches use one create-prd fileA.md fileB.md ...; list each PRD file/title/client_ref and make batch_count match the number of PRDs",
|
|
344
|
+
" - Feedback submit/revise/comment artifacts are usually the same YAML/markdown file being submitted; for inline text or stdin, use an approval memo with feedback_id/request_id and exact content",
|
|
345
|
+
" - Team, owner, and client update artifacts should name the audience and include the exact message body or complete summary; client updates should include target contact ids when used",
|
|
346
|
+
"",
|
|
347
|
+
"feedback action map:",
|
|
342
348
|
" - feedback-sync: pull board/PRD context into MyteCommandCenter for IDE work",
|
|
343
349
|
" - get: read one feedback item's current server snapshot and snapshot_hash",
|
|
344
350
|
" - status/edit/assign/archive/refine: create reviewable local YAML artifacts; no live mutation",
|
|
@@ -398,12 +404,12 @@ function printHelp() {
|
|
|
398
404
|
" --no-with-prd-text Skip PRD text download and write only feedback metadata/comment turns",
|
|
399
405
|
" --mission-ids <ids> Comma-separated mission business ids for run-qaqc, mission status, or mission archive (quote multi-id values on PowerShell)",
|
|
400
406
|
" --reason <text> Optional reason for governed mission archive or feedback changes",
|
|
401
|
-
" --actor-scope <id> Actor workspace key inside mission-ops.yml (defaults to machine-cwd slug)",
|
|
402
|
-
" --
|
|
407
|
+
" --actor-scope <id> Actor workspace key inside mission-ops.yml (defaults to machine-cwd slug)",
|
|
408
|
+
" --confirm-write Attach approval metadata for commands that require an approval artifact",
|
|
409
|
+
" --approval-artifact Local .md/.markdown/.yml/.yaml/.json approval artifact for gated write commands",
|
|
410
|
+
" --wait Poll batch status until terminal completion for run-qaqc",
|
|
403
411
|
" --sync After run-qaqc completes, refresh local QAQC file",
|
|
404
412
|
" --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
413
|
" --no-sync Skip automatic post-mutation sync for suggestions, missions, and feedback mutations",
|
|
408
414
|
" --print-context Print JSON payload and exit (no query call)",
|
|
409
415
|
" --no-fetch Don't git fetch origin main/master before diff",
|
|
@@ -414,33 +420,33 @@ function printHelp() {
|
|
|
414
420
|
" myte ai \"Return a JSON object with risks and next_steps\" --json-response",
|
|
415
421
|
" myte bootstrap",
|
|
416
422
|
" myte suggestions sync",
|
|
417
|
-
" myte suggestions create",
|
|
418
|
-
" myte suggestions revise --no-sync",
|
|
423
|
+
" myte suggestions create --file ./suggestions/create.yml --confirm-write --approval-artifact ./suggestions/create.yml",
|
|
424
|
+
" myte suggestions revise --file ./suggestions/revise.yml --confirm-write --approval-artifact ./suggestions/revise.yml --no-sync",
|
|
419
425
|
" myte suggestions review --file ./review.yml",
|
|
420
426
|
" myte run-qaqc --mission-ids \"M001,M002\" --wait --sync",
|
|
421
427
|
" myte mission status --mission-ids \"M001,M002\" --status done",
|
|
422
428
|
" myte mission archive --mission-ids \"M001\" --reason \"Duplicate disposable test mission\"",
|
|
423
429
|
" myte bootstrap --output-dir ./MyteCommandCenter",
|
|
424
430
|
" myte sync-qaqc",
|
|
425
|
-
" myte update-team \"Backend deploy completed; QAQC rerun queued.\"",
|
|
426
|
-
" myte update-owner --subject \"QAQC progress\" --body-file ./updates/owner.md",
|
|
427
|
-
" myte update-client --subject \"Weekly client update\" --body-file ./updates/week-12.md",
|
|
431
|
+
" myte update-team \"Backend deploy completed; QAQC rerun queued.\" --confirm-write --approval-artifact ./updates/team.md",
|
|
432
|
+
" myte update-owner --subject \"QAQC progress\" --body-file ./updates/owner.md --confirm-write --approval-artifact ./updates/owner.md",
|
|
433
|
+
" myte update-client --subject \"Weekly client update\" --body-file ./updates/week-12.md --confirm-write --approval-artifact ./updates/week-12.md",
|
|
428
434
|
" myte feedback-sync --json",
|
|
429
435
|
" myte feedback status --feedback-id 507f1f77bcf86cd799439011 --status in_review --reason \"Ready for owner review\"",
|
|
430
|
-
" myte feedback submit --file ./MyteCommandCenter/reviews/feedback/507f1f77bcf86cd799439011-edit.yml --json",
|
|
436
|
+
" myte feedback submit --file ./MyteCommandCenter/reviews/feedback/507f1f77bcf86cd799439011-edit.yml --confirm-write --approval-artifact ./MyteCommandCenter/reviews/feedback/507f1f77bcf86cd799439011-edit.yml --json",
|
|
431
437
|
" myte feedback reviews --status open --json",
|
|
432
438
|
" myte feedback review --request-id 507f1f77bcf86cd799439022 --action approve --reason \"Looks correct\" --json",
|
|
433
439
|
" myte feedback move --feedback-id 507f1f77bcf86cd799439011 --to-state in_progress --reason \"Started\" --json",
|
|
434
|
-
" myte feedback comment --feedback-id 507f1f77bcf86cd799439011 --body
|
|
440
|
+
" myte feedback comment --feedback-id 507f1f77bcf86cd799439011 --body-file ./comments/implementation.md --confirm-write --approval-artifact ./comments/implementation.md --json",
|
|
435
441
|
" myte feedback validate --file ./MyteCommandCenter/reviews/feedback/507f1f77bcf86cd799439011-status.yml --json",
|
|
436
442
|
" myte feedback apply --file ./MyteCommandCenter/reviews/feedback/507f1f77bcf86cd799439011-status.yml --json",
|
|
437
|
-
" myte suggestions create --file ./suggestions/create.yml",
|
|
438
|
-
" myte suggestions revise",
|
|
443
|
+
" myte suggestions create --file ./suggestions/create.yml --confirm-write --approval-artifact ./suggestions/create.yml",
|
|
444
|
+
" myte suggestions revise --file ./suggestions/revise.yml --confirm-write --approval-artifact ./suggestions/revise.yml",
|
|
439
445
|
" myte suggestions review",
|
|
440
|
-
" myte update-client --subject \"Weekly client update\" --body-markdown \"## Progress\\n- Login complete\" --target-contact-ids 507f1f77bcf86cd799439011,507f1f77bcf86cd799439012",
|
|
441
|
-
" myte create-prd ./drafts/auth-prd.md --description \"Short card summary\"",
|
|
442
|
-
" myte create-prd ./drafts/auth-prd.md ./drafts/billing-prd.md",
|
|
443
|
-
" cat ./drafts/auth-prd.md | myte create-prd --stdin",
|
|
446
|
+
" myte update-client --subject \"Weekly client update\" --body-markdown \"## Progress\\n- Login complete\" --target-contact-ids 507f1f77bcf86cd799439011,507f1f77bcf86cd799439012 --confirm-write --approval-artifact ./updates/week-12.md",
|
|
447
|
+
" myte create-prd ./drafts/auth-prd.md --description \"Short card summary\" --confirm-write --approval-artifact ./drafts/auth-prd.md",
|
|
448
|
+
" myte create-prd ./drafts/auth-prd.md ./drafts/billing-prd.md --confirm-write --approval-artifact ./drafts/prd-batch.md",
|
|
449
|
+
" cat ./drafts/auth-prd.md | myte create-prd --stdin --confirm-write --approval-artifact ./drafts/auth-prd.md",
|
|
444
450
|
" myte config",
|
|
445
451
|
].join("\n");
|
|
446
452
|
console.log(text);
|
|
@@ -701,164 +707,6 @@ async function fetchJsonWithTimeout(fetchFn, url, options, timeoutMs) {
|
|
|
701
707
|
}
|
|
702
708
|
}
|
|
703
709
|
|
|
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
|
-
function projectApiWritePayloadHash(payload) {
|
|
722
|
-
return createHash("sha256")
|
|
723
|
-
.update(pythonJsonDumpsCompatible(canonicalizeWritePayload(payload || {})))
|
|
724
|
-
.digest("hex");
|
|
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
710
|
function summarizeDiffDiagnosticsForContext(diagnostics) {
|
|
863
711
|
if (!diagnostics) return null;
|
|
864
712
|
const repos = Array.isArray(diagnostics.repo_summaries)
|
|
@@ -1922,7 +1770,7 @@ async function fetchFeedbackHistory({ apiBase, key, timeoutMs, feedbackId }) {
|
|
|
1922
1770
|
return body.data || {};
|
|
1923
1771
|
}
|
|
1924
1772
|
|
|
1925
|
-
async function postFeedbackRefinement({ apiBase, key, timeoutMs, feedbackId, mode, payload, idempotencyKey, clientSessionId
|
|
1773
|
+
async function postFeedbackRefinement({ apiBase, key, timeoutMs, feedbackId, mode, payload, idempotencyKey, clientSessionId }) {
|
|
1926
1774
|
const fetchFn = await getFetch();
|
|
1927
1775
|
const action = String(mode || "").trim();
|
|
1928
1776
|
const url = `${apiBase}/project-assistant/feedback/${encodeURIComponent(String(feedbackId || ""))}/refinement/${action}`;
|
|
@@ -1930,7 +1778,6 @@ async function postFeedbackRefinement({ apiBase, key, timeoutMs, feedbackId, mod
|
|
|
1930
1778
|
"Content-Type": "application/json",
|
|
1931
1779
|
Authorization: `Bearer ${key}`,
|
|
1932
1780
|
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
1933
|
-
...writeApprovalHeaders(writeApproval),
|
|
1934
1781
|
};
|
|
1935
1782
|
if (idempotencyKey) {
|
|
1936
1783
|
headers["X-Idempotency-Key"] = String(idempotencyKey).trim();
|
|
@@ -1947,7 +1794,7 @@ async function postFeedbackRefinement({ apiBase, key, timeoutMs, feedbackId, mod
|
|
|
1947
1794
|
);
|
|
1948
1795
|
|
|
1949
1796
|
if (!resp.ok || body.status !== "success") {
|
|
1950
|
-
const msg =
|
|
1797
|
+
const msg = body?.message || `Feedback refinement ${action} failed (${resp.status})`;
|
|
1951
1798
|
const err = new Error(msg);
|
|
1952
1799
|
err.status = resp.status;
|
|
1953
1800
|
err.data = body?.data;
|
|
@@ -2026,7 +1873,7 @@ async function fetchFeedbackEvents({ apiBase, key, timeoutMs, feedbackId, limit
|
|
|
2026
1873
|
return body.data || {};
|
|
2027
1874
|
}
|
|
2028
1875
|
|
|
2029
|
-
async function postFeedbackReviewSubmission({ apiBase, key, timeoutMs, feedbackId, payload, idempotencyKey, clientSessionId
|
|
1876
|
+
async function postFeedbackReviewSubmission({ apiBase, key, timeoutMs, feedbackId, payload, idempotencyKey, clientSessionId }) {
|
|
2030
1877
|
const fetchFn = await getFetch();
|
|
2031
1878
|
const url = `${apiBase}/project-assistant/feedback/${encodeURIComponent(String(feedbackId || ""))}/refinement/requests`;
|
|
2032
1879
|
const { resp, body } = await fetchJsonWithTimeout(
|
|
@@ -2039,7 +1886,6 @@ async function postFeedbackReviewSubmission({ apiBase, key, timeoutMs, feedbackI
|
|
|
2039
1886
|
Authorization: `Bearer ${key}`,
|
|
2040
1887
|
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2041
1888
|
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2042
|
-
...writeApprovalHeaders(writeApproval),
|
|
2043
1889
|
},
|
|
2044
1890
|
body: JSON.stringify(payload || {}),
|
|
2045
1891
|
},
|
|
@@ -2047,7 +1893,7 @@ async function postFeedbackReviewSubmission({ apiBase, key, timeoutMs, feedbackI
|
|
|
2047
1893
|
);
|
|
2048
1894
|
|
|
2049
1895
|
if (!resp.ok || body.status !== "success") {
|
|
2050
|
-
const msg =
|
|
1896
|
+
const msg = body?.message || `Feedback review submission failed (${resp.status})`;
|
|
2051
1897
|
const err = new Error(msg);
|
|
2052
1898
|
err.status = resp.status;
|
|
2053
1899
|
err.data = body?.data;
|
|
@@ -2056,7 +1902,7 @@ async function postFeedbackReviewSubmission({ apiBase, key, timeoutMs, feedbackI
|
|
|
2056
1902
|
return body.data || {};
|
|
2057
1903
|
}
|
|
2058
1904
|
|
|
2059
|
-
async function postFeedbackReviewRequestMutation({ apiBase, key, timeoutMs, requestId, endpointAction, payload, idempotencyKey, clientSessionId
|
|
1905
|
+
async function postFeedbackReviewRequestMutation({ apiBase, key, timeoutMs, requestId, endpointAction, payload, idempotencyKey, clientSessionId }) {
|
|
2060
1906
|
const fetchFn = await getFetch();
|
|
2061
1907
|
const url = `${apiBase}/project-assistant/feedback-review-requests/${encodeURIComponent(String(requestId || ""))}/${endpointAction}`;
|
|
2062
1908
|
const { resp, body } = await fetchJsonWithTimeout(
|
|
@@ -2069,7 +1915,6 @@ async function postFeedbackReviewRequestMutation({ apiBase, key, timeoutMs, requ
|
|
|
2069
1915
|
Authorization: `Bearer ${key}`,
|
|
2070
1916
|
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2071
1917
|
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2072
|
-
...writeApprovalHeaders(writeApproval),
|
|
2073
1918
|
},
|
|
2074
1919
|
body: JSON.stringify(payload || {}),
|
|
2075
1920
|
},
|
|
@@ -2077,7 +1922,7 @@ async function postFeedbackReviewRequestMutation({ apiBase, key, timeoutMs, requ
|
|
|
2077
1922
|
);
|
|
2078
1923
|
|
|
2079
1924
|
if (!resp.ok || body.status !== "success") {
|
|
2080
|
-
const msg =
|
|
1925
|
+
const msg = body?.message || `Feedback review ${endpointAction} failed (${resp.status})`;
|
|
2081
1926
|
const err = new Error(msg);
|
|
2082
1927
|
err.status = resp.status;
|
|
2083
1928
|
err.data = body?.data;
|
|
@@ -2086,7 +1931,7 @@ async function postFeedbackReviewRequestMutation({ apiBase, key, timeoutMs, requ
|
|
|
2086
1931
|
return body.data || {};
|
|
2087
1932
|
}
|
|
2088
1933
|
|
|
2089
|
-
async function postFeedbackBatchReviewMutation({ apiBase, key, timeoutMs, payload, idempotencyKey, clientSessionId
|
|
1934
|
+
async function postFeedbackBatchReviewMutation({ apiBase, key, timeoutMs, payload, idempotencyKey, clientSessionId }) {
|
|
2090
1935
|
const fetchFn = await getFetch();
|
|
2091
1936
|
const url = `${apiBase}/project-assistant/feedback-review-requests/batch-review`;
|
|
2092
1937
|
const { resp, body } = await fetchJsonWithTimeout(
|
|
@@ -2099,7 +1944,6 @@ async function postFeedbackBatchReviewMutation({ apiBase, key, timeoutMs, payloa
|
|
|
2099
1944
|
Authorization: `Bearer ${key}`,
|
|
2100
1945
|
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2101
1946
|
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2102
|
-
...writeApprovalHeaders(writeApproval),
|
|
2103
1947
|
},
|
|
2104
1948
|
body: JSON.stringify(payload || {}),
|
|
2105
1949
|
},
|
|
@@ -2107,7 +1951,7 @@ async function postFeedbackBatchReviewMutation({ apiBase, key, timeoutMs, payloa
|
|
|
2107
1951
|
);
|
|
2108
1952
|
|
|
2109
1953
|
if (!resp.ok || body.status !== "success") {
|
|
2110
|
-
const msg =
|
|
1954
|
+
const msg = body?.message || `Feedback batch review failed (${resp.status})`;
|
|
2111
1955
|
const err = new Error(msg);
|
|
2112
1956
|
err.status = resp.status;
|
|
2113
1957
|
err.data = body?.data;
|
|
@@ -2116,7 +1960,7 @@ async function postFeedbackBatchReviewMutation({ apiBase, key, timeoutMs, payloa
|
|
|
2116
1960
|
return body.data || {};
|
|
2117
1961
|
}
|
|
2118
1962
|
|
|
2119
|
-
async function postFeedbackBoardMutation({ apiBase, key, timeoutMs, feedbackId, endpoint, payload, idempotencyKey, clientSessionId
|
|
1963
|
+
async function postFeedbackBoardMutation({ apiBase, key, timeoutMs, feedbackId, endpoint, payload, idempotencyKey, clientSessionId }) {
|
|
2120
1964
|
const fetchFn = await getFetch();
|
|
2121
1965
|
const url = `${apiBase}/project-assistant/feedback/${encodeURIComponent(String(feedbackId || ""))}/${endpoint}`;
|
|
2122
1966
|
const { resp, body } = await fetchJsonWithTimeout(
|
|
@@ -2129,7 +1973,6 @@ async function postFeedbackBoardMutation({ apiBase, key, timeoutMs, feedbackId,
|
|
|
2129
1973
|
Authorization: `Bearer ${key}`,
|
|
2130
1974
|
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2131
1975
|
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2132
|
-
...writeApprovalHeaders(writeApproval),
|
|
2133
1976
|
},
|
|
2134
1977
|
body: JSON.stringify(payload || {}),
|
|
2135
1978
|
},
|
|
@@ -2137,7 +1980,7 @@ async function postFeedbackBoardMutation({ apiBase, key, timeoutMs, feedbackId,
|
|
|
2137
1980
|
);
|
|
2138
1981
|
|
|
2139
1982
|
if (!resp.ok || body.status !== "success") {
|
|
2140
|
-
const msg =
|
|
1983
|
+
const msg = body?.message || `Feedback board mutation failed (${resp.status})`;
|
|
2141
1984
|
const err = new Error(msg);
|
|
2142
1985
|
err.status = resp.status;
|
|
2143
1986
|
err.data = body?.data;
|
|
@@ -2146,7 +1989,7 @@ async function postFeedbackBoardMutation({ apiBase, key, timeoutMs, feedbackId,
|
|
|
2146
1989
|
return body.data || {};
|
|
2147
1990
|
}
|
|
2148
1991
|
|
|
2149
|
-
async function postFeedbackBatchBoardMutation({ apiBase, key, timeoutMs, payload, idempotencyKey, clientSessionId
|
|
1992
|
+
async function postFeedbackBatchBoardMutation({ apiBase, key, timeoutMs, payload, idempotencyKey, clientSessionId }) {
|
|
2150
1993
|
const fetchFn = await getFetch();
|
|
2151
1994
|
const url = `${apiBase}/project-assistant/feedback/batch-board-move`;
|
|
2152
1995
|
const { resp, body } = await fetchJsonWithTimeout(
|
|
@@ -2159,7 +2002,6 @@ async function postFeedbackBatchBoardMutation({ apiBase, key, timeoutMs, payload
|
|
|
2159
2002
|
Authorization: `Bearer ${key}`,
|
|
2160
2003
|
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2161
2004
|
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2162
|
-
...writeApprovalHeaders(writeApproval),
|
|
2163
2005
|
},
|
|
2164
2006
|
body: JSON.stringify(payload || {}),
|
|
2165
2007
|
},
|
|
@@ -2167,7 +2009,7 @@ async function postFeedbackBatchBoardMutation({ apiBase, key, timeoutMs, payload
|
|
|
2167
2009
|
);
|
|
2168
2010
|
|
|
2169
2011
|
if (!resp.ok || body.status !== "success") {
|
|
2170
|
-
const msg =
|
|
2012
|
+
const msg = body?.message || `Feedback batch board mutation failed (${resp.status})`;
|
|
2171
2013
|
const err = new Error(msg);
|
|
2172
2014
|
err.status = resp.status;
|
|
2173
2015
|
err.data = body?.data;
|
|
@@ -2176,7 +2018,7 @@ async function postFeedbackBatchBoardMutation({ apiBase, key, timeoutMs, payload
|
|
|
2176
2018
|
return body.data || {};
|
|
2177
2019
|
}
|
|
2178
2020
|
|
|
2179
|
-
async function postFeedbackComment({ apiBase, key, timeoutMs, feedbackId, payload, idempotencyKey, clientSessionId
|
|
2021
|
+
async function postFeedbackComment({ apiBase, key, timeoutMs, feedbackId, payload, idempotencyKey, clientSessionId }) {
|
|
2180
2022
|
const fetchFn = await getFetch();
|
|
2181
2023
|
const url = `${apiBase}/project-assistant/feedback/${encodeURIComponent(String(feedbackId || ""))}/comments`;
|
|
2182
2024
|
const { resp, body } = await fetchJsonWithTimeout(
|
|
@@ -2189,7 +2031,6 @@ async function postFeedbackComment({ apiBase, key, timeoutMs, feedbackId, payloa
|
|
|
2189
2031
|
Authorization: `Bearer ${key}`,
|
|
2190
2032
|
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2191
2033
|
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2192
|
-
...writeApprovalHeaders(writeApproval),
|
|
2193
2034
|
},
|
|
2194
2035
|
body: JSON.stringify(payload || {}),
|
|
2195
2036
|
},
|
|
@@ -2197,7 +2038,7 @@ async function postFeedbackComment({ apiBase, key, timeoutMs, feedbackId, payloa
|
|
|
2197
2038
|
);
|
|
2198
2039
|
|
|
2199
2040
|
if (!resp.ok || body.status !== "success") {
|
|
2200
|
-
const msg =
|
|
2041
|
+
const msg = body?.message || `Feedback comment failed (${resp.status})`;
|
|
2201
2042
|
const err = new Error(msg);
|
|
2202
2043
|
err.status = resp.status;
|
|
2203
2044
|
err.data = body?.data;
|
|
@@ -2303,7 +2144,7 @@ function resolveProjectMutationIdempotencyKey({ args, operation, payload }) {
|
|
|
2303
2144
|
return createHash("sha256").update(fingerprint).digest("hex");
|
|
2304
2145
|
}
|
|
2305
2146
|
|
|
2306
|
-
async function postSuggestionsMutation({ apiBase, key, timeoutMs, endpoint, payload, idempotencyKey, clientSessionId
|
|
2147
|
+
async function postSuggestionsMutation({ apiBase, key, timeoutMs, endpoint, payload, idempotencyKey, clientSessionId }) {
|
|
2307
2148
|
const fetchFn = await getFetch();
|
|
2308
2149
|
const url = `${apiBase}${endpoint}`;
|
|
2309
2150
|
const { resp, body } = await fetchJsonWithTimeout(
|
|
@@ -2316,7 +2157,6 @@ async function postSuggestionsMutation({ apiBase, key, timeoutMs, endpoint, payl
|
|
|
2316
2157
|
Authorization: `Bearer ${key}`,
|
|
2317
2158
|
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2318
2159
|
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2319
|
-
...writeApprovalHeaders(writeApproval),
|
|
2320
2160
|
},
|
|
2321
2161
|
body: JSON.stringify(payload),
|
|
2322
2162
|
},
|
|
@@ -2324,16 +2164,15 @@ async function postSuggestionsMutation({ apiBase, key, timeoutMs, endpoint, payl
|
|
|
2324
2164
|
);
|
|
2325
2165
|
|
|
2326
2166
|
if (!resp.ok || body.status !== "success") {
|
|
2327
|
-
const msg =
|
|
2167
|
+
const msg = body?.message || `Mission suggestions request failed (${resp.status})`;
|
|
2328
2168
|
const err = new Error(msg);
|
|
2329
2169
|
err.status = resp.status;
|
|
2330
|
-
err.data = body?.data;
|
|
2331
2170
|
throw err;
|
|
2332
2171
|
}
|
|
2333
2172
|
return body.data || {};
|
|
2334
2173
|
}
|
|
2335
2174
|
|
|
2336
|
-
async function createRunQaqcBatch({ apiBase, key, timeoutMs, payload, idempotencyKey, clientSessionId
|
|
2175
|
+
async function createRunQaqcBatch({ apiBase, key, timeoutMs, payload, idempotencyKey, clientSessionId }) {
|
|
2337
2176
|
const fetchFn = await getFetch();
|
|
2338
2177
|
const url = `${apiBase}/project-assistant/run-qaqc`;
|
|
2339
2178
|
const { resp, body } = await fetchJsonWithTimeout(
|
|
@@ -2346,7 +2185,6 @@ async function createRunQaqcBatch({ apiBase, key, timeoutMs, payload, idempotenc
|
|
|
2346
2185
|
Authorization: `Bearer ${key}`,
|
|
2347
2186
|
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2348
2187
|
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2349
|
-
...writeApprovalHeaders(writeApproval),
|
|
2350
2188
|
},
|
|
2351
2189
|
body: JSON.stringify(payload),
|
|
2352
2190
|
},
|
|
@@ -2354,16 +2192,15 @@ async function createRunQaqcBatch({ apiBase, key, timeoutMs, payload, idempotenc
|
|
|
2354
2192
|
);
|
|
2355
2193
|
|
|
2356
2194
|
if (!resp.ok || body.status !== "success") {
|
|
2357
|
-
const msg =
|
|
2195
|
+
const msg = body?.message || `Run QAQC request failed (${resp.status})`;
|
|
2358
2196
|
const err = new Error(msg);
|
|
2359
2197
|
err.status = resp.status;
|
|
2360
|
-
err.data = body?.data;
|
|
2361
2198
|
throw err;
|
|
2362
2199
|
}
|
|
2363
2200
|
return body.data || {};
|
|
2364
2201
|
}
|
|
2365
2202
|
|
|
2366
|
-
async function createMissionStatusUpdate({ apiBase, key, timeoutMs, payload, idempotencyKey, clientSessionId
|
|
2203
|
+
async function createMissionStatusUpdate({ apiBase, key, timeoutMs, payload, idempotencyKey, clientSessionId }) {
|
|
2367
2204
|
const fetchFn = await getFetch();
|
|
2368
2205
|
const url = `${apiBase}/project-assistant/mission-status-update`;
|
|
2369
2206
|
const { resp, body } = await fetchJsonWithTimeout(
|
|
@@ -2376,7 +2213,6 @@ async function createMissionStatusUpdate({ apiBase, key, timeoutMs, payload, ide
|
|
|
2376
2213
|
Authorization: `Bearer ${key}`,
|
|
2377
2214
|
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2378
2215
|
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2379
|
-
...writeApprovalHeaders(writeApproval),
|
|
2380
2216
|
},
|
|
2381
2217
|
body: JSON.stringify(payload),
|
|
2382
2218
|
},
|
|
@@ -2384,16 +2220,15 @@ async function createMissionStatusUpdate({ apiBase, key, timeoutMs, payload, ide
|
|
|
2384
2220
|
);
|
|
2385
2221
|
|
|
2386
2222
|
if (!resp.ok || body.status !== "success") {
|
|
2387
|
-
const msg =
|
|
2223
|
+
const msg = body?.message || `Mission status update request failed (${resp.status})`;
|
|
2388
2224
|
const err = new Error(msg);
|
|
2389
2225
|
err.status = resp.status;
|
|
2390
|
-
err.data = body?.data;
|
|
2391
2226
|
throw err;
|
|
2392
2227
|
}
|
|
2393
2228
|
return body.data || {};
|
|
2394
2229
|
}
|
|
2395
2230
|
|
|
2396
|
-
async function createMissionArchiveUpdate({ apiBase, key, timeoutMs, endpoint, payload, idempotencyKey, clientSessionId
|
|
2231
|
+
async function createMissionArchiveUpdate({ apiBase, key, timeoutMs, endpoint, payload, idempotencyKey, clientSessionId }) {
|
|
2397
2232
|
const fetchFn = await getFetch();
|
|
2398
2233
|
const url = `${apiBase}${endpoint}`;
|
|
2399
2234
|
const { resp, body } = await fetchJsonWithTimeout(
|
|
@@ -2406,7 +2241,6 @@ async function createMissionArchiveUpdate({ apiBase, key, timeoutMs, endpoint, p
|
|
|
2406
2241
|
Authorization: `Bearer ${key}`,
|
|
2407
2242
|
"X-Idempotency-Key": String(idempotencyKey || "").trim(),
|
|
2408
2243
|
...(String(clientSessionId || "").trim() ? { "X-Client-Session-Id": String(clientSessionId).trim() } : {}),
|
|
2409
|
-
...writeApprovalHeaders(writeApproval),
|
|
2410
2244
|
},
|
|
2411
2245
|
body: JSON.stringify(payload),
|
|
2412
2246
|
},
|
|
@@ -2414,10 +2248,9 @@ async function createMissionArchiveUpdate({ apiBase, key, timeoutMs, endpoint, p
|
|
|
2414
2248
|
);
|
|
2415
2249
|
|
|
2416
2250
|
if (!resp.ok || body.status !== "success") {
|
|
2417
|
-
const msg =
|
|
2251
|
+
const msg = body?.message || `Mission archive request failed (${resp.status})`;
|
|
2418
2252
|
const err = new Error(msg);
|
|
2419
2253
|
err.status = resp.status;
|
|
2420
|
-
err.data = body?.data;
|
|
2421
2254
|
throw err;
|
|
2422
2255
|
}
|
|
2423
2256
|
return body.data || {};
|
|
@@ -2530,15 +2363,15 @@ async function runRunQaqc(args) {
|
|
|
2530
2363
|
process.exit(1);
|
|
2531
2364
|
}
|
|
2532
2365
|
|
|
2533
|
-
|
|
2534
|
-
mission_ids: missionIds,
|
|
2535
|
-
force: Boolean(args.force),
|
|
2536
|
-
};
|
|
2537
|
-
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id);
|
|
2538
|
-
if (clientSessionId) payload.client_session_id = clientSessionId;
|
|
2539
|
-
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
2540
|
-
args,
|
|
2541
|
-
operation: "run-qaqc",
|
|
2366
|
+
let payload = {
|
|
2367
|
+
mission_ids: missionIds,
|
|
2368
|
+
force: Boolean(args.force),
|
|
2369
|
+
};
|
|
2370
|
+
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id);
|
|
2371
|
+
if (clientSessionId) payload.client_session_id = clientSessionId;
|
|
2372
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
2373
|
+
args,
|
|
2374
|
+
operation: "run-qaqc",
|
|
2542
2375
|
payload,
|
|
2543
2376
|
});
|
|
2544
2377
|
|
|
@@ -2551,12 +2384,6 @@ async function runRunQaqc(args) {
|
|
|
2551
2384
|
const apiBase = resolveApiBase(args);
|
|
2552
2385
|
const shouldWait = Boolean(args.wait || args.sync);
|
|
2553
2386
|
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
2387
|
|
|
2561
2388
|
let data;
|
|
2562
2389
|
try {
|
|
@@ -2567,7 +2394,6 @@ async function runRunQaqc(args) {
|
|
|
2567
2394
|
payload,
|
|
2568
2395
|
idempotencyKey,
|
|
2569
2396
|
clientSessionId,
|
|
2570
|
-
writeApproval,
|
|
2571
2397
|
});
|
|
2572
2398
|
} catch (err) {
|
|
2573
2399
|
if (err?.name === "AbortError") {
|
|
@@ -2692,15 +2518,15 @@ async function runMissionStatus(args) {
|
|
|
2692
2518
|
process.exit(1);
|
|
2693
2519
|
}
|
|
2694
2520
|
|
|
2695
|
-
|
|
2696
|
-
mission_ids: missionIds,
|
|
2697
|
-
new_status: newStatus,
|
|
2698
|
-
};
|
|
2699
|
-
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id);
|
|
2700
|
-
if (clientSessionId) payload.client_session_id = clientSessionId;
|
|
2701
|
-
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
2702
|
-
args,
|
|
2703
|
-
operation: "mission-status-update",
|
|
2521
|
+
let payload = {
|
|
2522
|
+
mission_ids: missionIds,
|
|
2523
|
+
new_status: newStatus,
|
|
2524
|
+
};
|
|
2525
|
+
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id);
|
|
2526
|
+
if (clientSessionId) payload.client_session_id = clientSessionId;
|
|
2527
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
2528
|
+
args,
|
|
2529
|
+
operation: "mission-status-update",
|
|
2704
2530
|
payload,
|
|
2705
2531
|
});
|
|
2706
2532
|
|
|
@@ -2711,12 +2537,6 @@ async function runMissionStatus(args) {
|
|
|
2711
2537
|
|
|
2712
2538
|
const timeoutMs = resolveTimeoutMs(args);
|
|
2713
2539
|
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
2540
|
|
|
2721
2541
|
let data;
|
|
2722
2542
|
try {
|
|
@@ -2727,7 +2547,6 @@ async function runMissionStatus(args) {
|
|
|
2727
2547
|
payload,
|
|
2728
2548
|
idempotencyKey,
|
|
2729
2549
|
clientSessionId,
|
|
2730
|
-
writeApproval,
|
|
2731
2550
|
});
|
|
2732
2551
|
} catch (err) {
|
|
2733
2552
|
if (err?.name === "AbortError") {
|
|
@@ -2802,17 +2621,16 @@ async function runMissionArchiveCommand(args) {
|
|
|
2802
2621
|
process.exit(1);
|
|
2803
2622
|
}
|
|
2804
2623
|
|
|
2805
|
-
|
|
2806
|
-
mission_ids: missionIds,
|
|
2807
|
-
};
|
|
2808
|
-
const reason = firstNonEmptyString(args.reason);
|
|
2809
|
-
if (reason) payload.reason = reason;
|
|
2810
|
-
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id);
|
|
2811
|
-
if (clientSessionId) payload.client_session_id = clientSessionId;
|
|
2812
|
-
|
|
2813
|
-
const
|
|
2814
|
-
|
|
2815
|
-
args,
|
|
2624
|
+
let payload = {
|
|
2625
|
+
mission_ids: missionIds,
|
|
2626
|
+
};
|
|
2627
|
+
const reason = firstNonEmptyString(args.reason);
|
|
2628
|
+
if (reason) payload.reason = reason;
|
|
2629
|
+
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id);
|
|
2630
|
+
if (clientSessionId) payload.client_session_id = clientSessionId;
|
|
2631
|
+
const operation = "mission-archive";
|
|
2632
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
2633
|
+
args,
|
|
2816
2634
|
operation,
|
|
2817
2635
|
payload,
|
|
2818
2636
|
});
|
|
@@ -2825,12 +2643,6 @@ async function runMissionArchiveCommand(args) {
|
|
|
2825
2643
|
const timeoutMs = resolveTimeoutMs(args);
|
|
2826
2644
|
const apiBase = resolveApiBase(args);
|
|
2827
2645
|
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
2646
|
|
|
2835
2647
|
let data;
|
|
2836
2648
|
try {
|
|
@@ -2842,7 +2654,6 @@ async function runMissionArchiveCommand(args) {
|
|
|
2842
2654
|
payload,
|
|
2843
2655
|
idempotencyKey,
|
|
2844
2656
|
clientSessionId,
|
|
2845
|
-
writeApproval,
|
|
2846
2657
|
});
|
|
2847
2658
|
} catch (err) {
|
|
2848
2659
|
if (err?.name === "AbortError") {
|
|
@@ -2924,9 +2735,9 @@ async function runUpdateTeam(args) {
|
|
|
2924
2735
|
process.exit(1);
|
|
2925
2736
|
}
|
|
2926
2737
|
|
|
2927
|
-
|
|
2928
|
-
content: await resolveTeamUpdateContent(args),
|
|
2929
|
-
};
|
|
2738
|
+
let payload = {
|
|
2739
|
+
content: await resolveTeamUpdateContent(args),
|
|
2740
|
+
};
|
|
2930
2741
|
|
|
2931
2742
|
if (args["print-context"] || args.printContext || args["dry-run"] || args.dryRun) {
|
|
2932
2743
|
console.log(JSON.stringify(payload, null, 2));
|
|
@@ -2934,18 +2745,18 @@ async function runUpdateTeam(args) {
|
|
|
2934
2745
|
}
|
|
2935
2746
|
|
|
2936
2747
|
const timeoutMs = resolveTimeoutMs(args);
|
|
2937
|
-
const apiBase = resolveApiBase(args);
|
|
2938
|
-
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id);
|
|
2939
|
-
if (clientSessionId) payload.client_session_id = clientSessionId;
|
|
2940
|
-
|
|
2748
|
+
const apiBase = resolveApiBase(args);
|
|
2749
|
+
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id);
|
|
2750
|
+
if (clientSessionId) payload.client_session_id = clientSessionId;
|
|
2751
|
+
payload = withWriteApproval(args, payload, {
|
|
2752
|
+
artifactKind: "markdown",
|
|
2753
|
+
targets: ["project"],
|
|
2754
|
+
});
|
|
2755
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
2941
2756
|
args,
|
|
2942
2757
|
operation: "update_team",
|
|
2943
2758
|
payload,
|
|
2944
2759
|
});
|
|
2945
|
-
const writeApproval = requireWriteApproval(args, payload, {
|
|
2946
|
-
operation: "update_team",
|
|
2947
|
-
artifactKind: "markdown",
|
|
2948
|
-
});
|
|
2949
2760
|
|
|
2950
2761
|
let data;
|
|
2951
2762
|
try {
|
|
@@ -2957,7 +2768,6 @@ async function runUpdateTeam(args) {
|
|
|
2957
2768
|
endpoint: "/project-assistant/project-comment",
|
|
2958
2769
|
idempotencyKey,
|
|
2959
2770
|
clientSessionId,
|
|
2960
|
-
writeApproval,
|
|
2961
2771
|
});
|
|
2962
2772
|
} catch (err) {
|
|
2963
2773
|
if (err?.name === "AbortError") {
|
|
@@ -2997,10 +2807,10 @@ async function runUpdateOwner(args) {
|
|
|
2997
2807
|
process.exit(1);
|
|
2998
2808
|
}
|
|
2999
2809
|
|
|
3000
|
-
|
|
3001
|
-
subject,
|
|
3002
|
-
body_markdown: await resolveOwnerUpdateBody(args),
|
|
3003
|
-
};
|
|
2810
|
+
let payload = {
|
|
2811
|
+
subject,
|
|
2812
|
+
body_markdown: await resolveOwnerUpdateBody(args),
|
|
2813
|
+
};
|
|
3004
2814
|
|
|
3005
2815
|
if (args["print-context"] || args.printContext || args["dry-run"] || args.dryRun) {
|
|
3006
2816
|
console.log(JSON.stringify(payload, null, 2));
|
|
@@ -3008,18 +2818,18 @@ async function runUpdateOwner(args) {
|
|
|
3008
2818
|
}
|
|
3009
2819
|
|
|
3010
2820
|
const timeoutMs = resolveTimeoutMs(args);
|
|
3011
|
-
const apiBase = resolveApiBase(args);
|
|
3012
|
-
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id);
|
|
3013
|
-
if (clientSessionId) payload.client_session_id = clientSessionId;
|
|
3014
|
-
|
|
2821
|
+
const apiBase = resolveApiBase(args);
|
|
2822
|
+
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id);
|
|
2823
|
+
if (clientSessionId) payload.client_session_id = clientSessionId;
|
|
2824
|
+
payload = withWriteApproval(args, payload, {
|
|
2825
|
+
artifactKind: "markdown",
|
|
2826
|
+
targets: ["project"],
|
|
2827
|
+
});
|
|
2828
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
3015
2829
|
args,
|
|
3016
2830
|
operation: "update_owner",
|
|
3017
2831
|
payload,
|
|
3018
2832
|
});
|
|
3019
|
-
const writeApproval = requireWriteApproval(args, payload, {
|
|
3020
|
-
operation: "update_owner",
|
|
3021
|
-
artifactKind: "markdown",
|
|
3022
|
-
});
|
|
3023
2833
|
|
|
3024
2834
|
let data;
|
|
3025
2835
|
try {
|
|
@@ -3031,7 +2841,6 @@ async function runUpdateOwner(args) {
|
|
|
3031
2841
|
endpoint: "/project-assistant/update-owner",
|
|
3032
2842
|
idempotencyKey,
|
|
3033
2843
|
clientSessionId,
|
|
3034
|
-
writeApproval,
|
|
3035
2844
|
});
|
|
3036
2845
|
} catch (err) {
|
|
3037
2846
|
if (err?.name === "AbortError") {
|
|
@@ -3079,11 +2888,11 @@ async function runUpdateClient(args) {
|
|
|
3079
2888
|
process.exit(1);
|
|
3080
2889
|
}
|
|
3081
2890
|
|
|
3082
|
-
|
|
3083
|
-
subject,
|
|
3084
|
-
body_markdown: await resolveClientUpdateBody(args),
|
|
3085
|
-
target_contact_ids: resolveTargetContactIds(args),
|
|
3086
|
-
};
|
|
2891
|
+
let payload = {
|
|
2892
|
+
subject,
|
|
2893
|
+
body_markdown: await resolveClientUpdateBody(args),
|
|
2894
|
+
target_contact_ids: resolveTargetContactIds(args),
|
|
2895
|
+
};
|
|
3087
2896
|
|
|
3088
2897
|
if (args["print-context"] || args.printContext || args["dry-run"] || args.dryRun) {
|
|
3089
2898
|
console.log(JSON.stringify(payload, null, 2));
|
|
@@ -3091,18 +2900,18 @@ async function runUpdateClient(args) {
|
|
|
3091
2900
|
}
|
|
3092
2901
|
|
|
3093
2902
|
const timeoutMs = resolveTimeoutMs(args);
|
|
3094
|
-
const apiBase = resolveApiBase(args);
|
|
3095
|
-
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id);
|
|
3096
|
-
if (clientSessionId) payload.client_session_id = clientSessionId;
|
|
3097
|
-
|
|
2903
|
+
const apiBase = resolveApiBase(args);
|
|
2904
|
+
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id);
|
|
2905
|
+
if (clientSessionId) payload.client_session_id = clientSessionId;
|
|
2906
|
+
payload = withWriteApproval(args, payload, {
|
|
2907
|
+
artifactKind: "markdown",
|
|
2908
|
+
targets: ["project"],
|
|
2909
|
+
});
|
|
2910
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
3098
2911
|
args,
|
|
3099
2912
|
operation: "update_client",
|
|
3100
2913
|
payload,
|
|
3101
2914
|
});
|
|
3102
|
-
const writeApproval = requireWriteApproval(args, payload, {
|
|
3103
|
-
operation: "update_client",
|
|
3104
|
-
artifactKind: "markdown",
|
|
3105
|
-
});
|
|
3106
2915
|
|
|
3107
2916
|
let data;
|
|
3108
2917
|
try {
|
|
@@ -3114,7 +2923,6 @@ async function runUpdateClient(args) {
|
|
|
3114
2923
|
endpoint: "/project-assistant/client-update-drafts",
|
|
3115
2924
|
idempotencyKey,
|
|
3116
2925
|
clientSessionId,
|
|
3117
|
-
writeApproval,
|
|
3118
2926
|
});
|
|
3119
2927
|
} catch (err) {
|
|
3120
2928
|
if (err?.name === "AbortError") {
|
|
@@ -3210,7 +3018,7 @@ function stringifyYaml(value) {
|
|
|
3210
3018
|
function stableJsonStringify(value) {
|
|
3211
3019
|
if (Array.isArray(value)) {
|
|
3212
3020
|
return `[${value.map((item) => stableJsonStringify(item)).join(",")}]`;
|
|
3213
|
-
}
|
|
3021
|
+
}
|
|
3214
3022
|
if (value && typeof value === "object") {
|
|
3215
3023
|
const entries = Object.keys(value)
|
|
3216
3024
|
.sort()
|
|
@@ -3220,38 +3028,137 @@ function stableJsonStringify(value) {
|
|
|
3220
3028
|
return JSON.stringify(value);
|
|
3221
3029
|
}
|
|
3222
3030
|
|
|
3223
|
-
function
|
|
3031
|
+
function pythonJsonStringify(value) {
|
|
3032
|
+
if (Array.isArray(value)) {
|
|
3033
|
+
return `[${value.map((item) => pythonJsonStringify(item)).join(", ")}]`;
|
|
3034
|
+
}
|
|
3035
|
+
if (value && typeof value === "object") {
|
|
3036
|
+
const entries = Object.keys(value)
|
|
3037
|
+
.filter((key) => value[key] !== undefined)
|
|
3038
|
+
.sort()
|
|
3039
|
+
.map((key) => `${jsonStringEnsureAscii(key)}: ${pythonJsonStringify(value[key])}`);
|
|
3040
|
+
return `{${entries.join(", ")}}`;
|
|
3041
|
+
}
|
|
3042
|
+
if (typeof value === "string") return jsonStringEnsureAscii(value);
|
|
3043
|
+
if (value === undefined) return "null";
|
|
3044
|
+
return JSON.stringify(value);
|
|
3045
|
+
}
|
|
3046
|
+
|
|
3047
|
+
function jsonStringEnsureAscii(value) {
|
|
3224
3048
|
return JSON.stringify(String(value)).replace(/[^\x00-\x7F]/g, (char) => {
|
|
3225
3049
|
const code = char.charCodeAt(0);
|
|
3226
3050
|
return `\\u${code.toString(16).padStart(4, "0")}`;
|
|
3227
3051
|
});
|
|
3228
3052
|
}
|
|
3229
3053
|
|
|
3230
|
-
function
|
|
3054
|
+
function canonicalizeWritePayload(value) {
|
|
3231
3055
|
if (Array.isArray(value)) {
|
|
3232
|
-
return
|
|
3056
|
+
return value.map((item) => canonicalizeWritePayload(item));
|
|
3233
3057
|
}
|
|
3234
3058
|
if (value && typeof value === "object") {
|
|
3235
|
-
const
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3059
|
+
const next = {};
|
|
3060
|
+
for (const key of Object.keys(value)) {
|
|
3061
|
+
if (key === "write_approval" || key === "client_session_id") continue;
|
|
3062
|
+
if (value[key] === undefined) continue;
|
|
3063
|
+
next[key] = canonicalizeWritePayload(value[key]);
|
|
3064
|
+
}
|
|
3065
|
+
return next;
|
|
3066
|
+
}
|
|
3067
|
+
return value;
|
|
3068
|
+
}
|
|
3069
|
+
|
|
3070
|
+
function projectWritePayloadHash(payload) {
|
|
3071
|
+
const canonical = canonicalizeWritePayload(payload || {});
|
|
3072
|
+
return createHash("sha256").update(pythonJsonStringify(canonical)).digest("hex");
|
|
3073
|
+
}
|
|
3074
|
+
|
|
3075
|
+
function approvalArtifactKind(artifactPath, fallback = "yaml") {
|
|
3076
|
+
const ext = path.extname(String(artifactPath || "")).toLowerCase();
|
|
3077
|
+
if (ext === ".md" || ext === ".markdown") return "markdown";
|
|
3078
|
+
if (ext === ".json") return "json";
|
|
3079
|
+
if (ext === ".yml" || ext === ".yaml") return "yaml";
|
|
3080
|
+
return fallback || "yaml";
|
|
3081
|
+
}
|
|
3082
|
+
|
|
3083
|
+
function resolveWriteApprovalArtifact(args) {
|
|
3084
|
+
const artifactPath = firstNonEmptyString(
|
|
3085
|
+
args["approval-artifact"],
|
|
3086
|
+
args.approvalArtifact,
|
|
3087
|
+
args.approval_artifact
|
|
3088
|
+
);
|
|
3089
|
+
if (!artifactPath) {
|
|
3090
|
+
console.error("Missing --approval-artifact for confirmed live Myte write.");
|
|
3091
|
+
process.exit(1);
|
|
3239
3092
|
}
|
|
3240
|
-
|
|
3241
|
-
if (
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
if (value === Infinity) return "Infinity";
|
|
3245
|
-
if (value === -Infinity) return "-Infinity";
|
|
3246
|
-
return JSON.stringify(value);
|
|
3093
|
+
const absPath = path.resolve(String(artifactPath));
|
|
3094
|
+
if (!fs.existsSync(absPath) || !fs.statSync(absPath).isFile()) {
|
|
3095
|
+
console.error(`Approval artifact not found: ${absPath}`);
|
|
3096
|
+
process.exit(1);
|
|
3247
3097
|
}
|
|
3248
|
-
|
|
3098
|
+
const ext = path.extname(absPath).toLowerCase();
|
|
3099
|
+
if (![".md", ".markdown", ".yml", ".yaml", ".json"].includes(ext)) {
|
|
3100
|
+
console.error("Approval artifact must be a local .md, .markdown, .yml, .yaml, or .json file.");
|
|
3101
|
+
process.exit(1);
|
|
3102
|
+
}
|
|
3103
|
+
return { displayPath: String(artifactPath), absPath };
|
|
3104
|
+
}
|
|
3105
|
+
|
|
3106
|
+
function approvalTargets(values) {
|
|
3107
|
+
return uniqueNormalizedStrings(Array.isArray(values) ? values : [values]);
|
|
3108
|
+
}
|
|
3109
|
+
|
|
3110
|
+
function hasWriteApprovalArtifactArg(args) {
|
|
3111
|
+
return Boolean(firstNonEmptyString(
|
|
3112
|
+
args["approval-artifact"],
|
|
3113
|
+
args.approvalArtifact,
|
|
3114
|
+
args.approval_artifact
|
|
3115
|
+
));
|
|
3116
|
+
}
|
|
3117
|
+
|
|
3118
|
+
function withWriteApproval(args, payload, { artifactKind = "yaml", targets = [], batchCount = null, required = true } = {}) {
|
|
3119
|
+
const confirmed = Boolean(args["confirm-write"] || args.confirmWrite || args.confirm_write);
|
|
3120
|
+
if (required && (!confirmed || !hasWriteApprovalArtifactArg(args))) {
|
|
3121
|
+
console.error("Missing --confirm-write --approval-artifact <path> for this live Myte write.");
|
|
3122
|
+
process.exit(1);
|
|
3123
|
+
}
|
|
3124
|
+
if (!confirmed) return payload;
|
|
3125
|
+
const { displayPath } = resolveWriteApprovalArtifact(args);
|
|
3126
|
+
const nextPayload = { ...(payload || {}) };
|
|
3127
|
+
const normalizedTargets = approvalTargets(targets);
|
|
3128
|
+
const approval = {
|
|
3129
|
+
approved: true,
|
|
3130
|
+
source: "explicit_user_approval",
|
|
3131
|
+
artifact_path: displayPath,
|
|
3132
|
+
artifact_kind: approvalArtifactKind(displayPath, artifactKind),
|
|
3133
|
+
payload_sha256: projectWritePayloadHash(nextPayload),
|
|
3134
|
+
};
|
|
3135
|
+
if (normalizedTargets.length) approval.targets = normalizedTargets;
|
|
3136
|
+
if (batchCount !== undefined && batchCount !== null) approval.batch_count = Number(batchCount);
|
|
3137
|
+
nextPayload.write_approval = approval;
|
|
3138
|
+
return nextPayload;
|
|
3139
|
+
}
|
|
3140
|
+
|
|
3141
|
+
function suggestionWriteTargets(items) {
|
|
3142
|
+
return (Array.isArray(items) ? items : [])
|
|
3143
|
+
.map((item, index) => {
|
|
3144
|
+
if (!item || typeof item !== "object") return `index:${index}`;
|
|
3145
|
+
const changeType = String(item.change_type || item.action || "suggestion").trim().toLowerCase() || "suggestion";
|
|
3146
|
+
const changeSet = item.change_set && typeof item.change_set === "object" ? item.change_set : item;
|
|
3147
|
+
return firstNonEmptyString(
|
|
3148
|
+
item.suggestion_id,
|
|
3149
|
+
item.mission_id,
|
|
3150
|
+
item.client_ref,
|
|
3151
|
+
changeSet.title ? `${changeType}:${String(changeSet.title).slice(0, 80)}` : "",
|
|
3152
|
+
`index:${index}`
|
|
3153
|
+
);
|
|
3154
|
+
})
|
|
3155
|
+
.filter(Boolean);
|
|
3249
3156
|
}
|
|
3250
3157
|
|
|
3251
3158
|
function parseYaml(text) {
|
|
3252
|
-
const raw = String(text || "").trim();
|
|
3253
|
-
if (!raw) return null;
|
|
3254
|
-
if (raw.startsWith("{") || raw.startsWith("[")) {
|
|
3159
|
+
const raw = String(text || "").trim();
|
|
3160
|
+
if (!raw) return null;
|
|
3161
|
+
if (raw.startsWith("{") || raw.startsWith("[")) {
|
|
3255
3162
|
return JSON.parse(raw);
|
|
3256
3163
|
}
|
|
3257
3164
|
return parseSimpleYaml(raw);
|
|
@@ -3519,19 +3426,123 @@ function resolvePortableWorkspace(repoNames) {
|
|
|
3519
3426
|
};
|
|
3520
3427
|
}
|
|
3521
3428
|
|
|
3522
|
-
function resolveCommandCenterRoots(wrapperRoot, outputDir) {
|
|
3523
|
-
const targetRoot = outputDir
|
|
3524
|
-
? path.resolve(process.cwd(), String(outputDir))
|
|
3525
|
-
: path.join(wrapperRoot, "MyteCommandCenter");
|
|
3526
|
-
return {
|
|
3527
|
-
targetRoot,
|
|
3528
|
-
dataRoot: path.join(targetRoot, "data"),
|
|
3529
|
-
};
|
|
3530
|
-
}
|
|
3531
|
-
|
|
3532
|
-
function
|
|
3533
|
-
|
|
3534
|
-
|
|
3429
|
+
function resolveCommandCenterRoots(wrapperRoot, outputDir) {
|
|
3430
|
+
const targetRoot = outputDir
|
|
3431
|
+
? path.resolve(process.cwd(), String(outputDir))
|
|
3432
|
+
: path.join(wrapperRoot, "MyteCommandCenter");
|
|
3433
|
+
return {
|
|
3434
|
+
targetRoot,
|
|
3435
|
+
dataRoot: path.join(targetRoot, "data"),
|
|
3436
|
+
};
|
|
3437
|
+
}
|
|
3438
|
+
|
|
3439
|
+
function buildAgentsMyteApiMarkdown() {
|
|
3440
|
+
return ensureTrailingNewline([
|
|
3441
|
+
"# AgentsMyteAPI",
|
|
3442
|
+
"",
|
|
3443
|
+
"This file is generated by `myte bootstrap` as contextual guidance for coding agents using a project-scoped Myte API key.",
|
|
3444
|
+
"It does not grant permission, approve a write, or replace project authorization. Prefer the `myte` CLI over direct HTTP.",
|
|
3445
|
+
"",
|
|
3446
|
+
"## Auth And Discovery",
|
|
3447
|
+
"",
|
|
3448
|
+
"- Use `MYTE_API_KEY` or `MYTE_PROJECT_API_KEY` for `/api/project-assistant/*`.",
|
|
3449
|
+
"- Default API base: `https://api.myte.dev/api`.",
|
|
3450
|
+
"- Start with `myte config --json`, then `myte bootstrap --json`.",
|
|
3451
|
+
"- Use local IDs from `MyteCommandCenter/data/missions/*.yml`, `data/mission-ops.yml`, and `data/feedback.yml`.",
|
|
3452
|
+
"- `myte ai` is intentionally outside this project-scoped table. It uses `MYTEAI_API_KEY` and the Myte AI gateway, not `/api/project-assistant/*`.",
|
|
3453
|
+
"",
|
|
3454
|
+
"## Approval Artifact Rule",
|
|
3455
|
+
"",
|
|
3456
|
+
"Only the commands marked `required` below need `--confirm-write --approval-artifact <path>`.",
|
|
3457
|
+
"Approval artifacts are local `.md`, `.markdown`, `.yml`, `.yaml`, or `.json` files that list the operation, exact target IDs, proposed change, and batch count when relevant.",
|
|
3458
|
+
"The artifact is the human-reviewed record of the intended mutation. It does not grant permission, bypass owner/delegate checks, or replace idempotency; it gives the API enough evidence that a human approved this exact write payload.",
|
|
3459
|
+
"",
|
|
3460
|
+
"Minimum artifact contents for required actions:",
|
|
3461
|
+
"",
|
|
3462
|
+
"- `command`: the exact CLI command you plan to run.",
|
|
3463
|
+
"- `targets`: every affected project, feedback, request, suggestion, mission, PRD file, client ref, or contact id.",
|
|
3464
|
+
"- `proposed_change`: a complete summary of the text/status/content being sent.",
|
|
3465
|
+
"- `batch_count`: required when the command sends more than one item in one API call.",
|
|
3466
|
+
"- `reason` or `approval_note`: why the write is being sent now.",
|
|
3467
|
+
"",
|
|
3468
|
+
"Batch guidance:",
|
|
3469
|
+
"",
|
|
3470
|
+
"- Mission edit/create batches use `myte suggestions create` or `myte suggestions revise`; the artifact must list each item. For mission edits include `change_type: update`, the existing `mission_id`, and the changed fields. For new missions include `change_type: create`, the proposed title, description, and acceptance details. For revisions include each `suggestion_id` and expected revision.",
|
|
3471
|
+
"- PRD batches use one `myte create-prd fileA.md fileB.md ...`; the artifact must list each PRD file/title/client ref. `batch_count` must match the number of PRD items.",
|
|
3472
|
+
"- Feedback submit/revise/comment artifacts are usually the same YAML or markdown file being submitted. If the command uses inline text or stdin, create a separate approval memo that includes the feedback id or request id and the exact content.",
|
|
3473
|
+
"- Team, owner, and client update artifacts should name the audience and include the exact message body or a complete summary; client updates should include target contact ids when used.",
|
|
3474
|
+
"- `feedback review --request-ids`, `feedback move --feedback-ids`, `mission status --mission-ids`, `mission archive --mission-ids`, and `run-qaqc --mission-ids` are batched governed writes, but they are marked `no` below and should not receive approval artifact flags.",
|
|
3475
|
+
"",
|
|
3476
|
+
"Example approval artifact:",
|
|
3477
|
+
"",
|
|
3478
|
+
"```yaml",
|
|
3479
|
+
"command: myte suggestions create --file ./mission-suggestions.yml --confirm-write --approval-artifact ./mission-suggestions-approval.yml",
|
|
3480
|
+
"reason: Human approved this mission review batch after inspecting the proposed changes.",
|
|
3481
|
+
"batch_count: 2",
|
|
3482
|
+
"targets:",
|
|
3483
|
+
" - mission_id: M093",
|
|
3484
|
+
" change_type: update",
|
|
3485
|
+
" proposed_change: Mark acceptance criteria complete and clarify final QA note.",
|
|
3486
|
+
" - new_mission: Add deployment verification",
|
|
3487
|
+
" change_type: create",
|
|
3488
|
+
" proposed_change: Create a mission to verify deploy logs, smoke test, and rollback note.",
|
|
3489
|
+
"```",
|
|
3490
|
+
"",
|
|
3491
|
+
"| Action | CLI shape | API route | Class | Artifact approval |",
|
|
3492
|
+
"|---|---|---|---|---|",
|
|
3493
|
+
"| Config | `myte config --json` | `GET /project-assistant/config` | read | no |",
|
|
3494
|
+
"| Query | `myte query \"...\" --with-diff` | `POST /project-assistant/query`; polls `GET /project-assistant/query/<job_id>` when queued; `--with-diff` also reads `GET /project-assistant/config` | query job | no |",
|
|
3495
|
+
"| Bootstrap | `myte bootstrap --json` | `GET /project-assistant/bootstrap` and `GET /project-assistant/suggestions` | local sync | no |",
|
|
3496
|
+
"| QAQC sync | `myte sync-qaqc --json` | `GET /project-assistant/qaqc-sync` | local sync | no |",
|
|
3497
|
+
"| Run QAQC | `myte run-qaqc --mission-ids \"M001,M002\" --wait --sync --json` | `POST /project-assistant/run-qaqc`; `--wait` polls `GET /project-assistant/run-qaqc/<batch_id>`; `--sync` reads `GET /project-assistant/qaqc-sync` | governed write | no |",
|
|
3498
|
+
"| Mission status | `myte mission status --mission-ids \"M001\" --status done --json` | `POST /project-assistant/mission-status-update` | governed write | no |",
|
|
3499
|
+
"| Mission archive | `myte mission archive --mission-ids \"M001\" --reason \"...\" --json` | `POST /project-assistant/mission-archive` | governed write | no |",
|
|
3500
|
+
"| Suggestions sync | `myte suggestions sync --json` | `GET /project-assistant/suggestions` | local sync | no |",
|
|
3501
|
+
"| Suggestions create | `myte suggestions create --file ./create.yml --confirm-write --approval-artifact ./create.yml --json` | `POST /project-assistant/suggestions` | review-thread write | required |",
|
|
3502
|
+
"| Suggestions revise | `myte suggestions revise --file ./revise.yml --confirm-write --approval-artifact ./revise.yml --json` | `POST /project-assistant/suggestions/revise` | review-thread write | required |",
|
|
3503
|
+
"| Suggestions review | `myte suggestions review --file ./review.yml --json` | `POST /project-assistant/suggestions/review` | governed review write | no |",
|
|
3504
|
+
"| Feedback sync | `myte feedback-sync --json` | `GET /project-assistant/feedback-sync` | local sync | no |",
|
|
3505
|
+
"| Feedback get | `myte feedback get --feedback-id <id> --json` | `GET /project-assistant/feedback/<id>` | read | no |",
|
|
3506
|
+
"| Feedback history | `myte feedback history --feedback-id <id> --json` | `GET /project-assistant/feedback/<id>/events` | read | no |",
|
|
3507
|
+
"| Feedback local drafts | `myte feedback status/edit/assign/archive/refine ...` | none | local artifact only | no |",
|
|
3508
|
+
"| Feedback validate | `myte feedback validate --file ./review.yml --json` | `POST /project-assistant/feedback/<id>/refinement/validate` | validation | no |",
|
|
3509
|
+
"| Feedback submit | `myte feedback submit --file ./review.yml --confirm-write --approval-artifact ./review.yml --json` | `POST /project-assistant/feedback/<id>/refinement/requests` | review-request write | required |",
|
|
3510
|
+
"| Feedback revise | `myte feedback revise --request-id <id> --file ./review.yml --confirm-write --approval-artifact ./review.yml --json` | `POST /project-assistant/feedback-review-requests/<id>/revise` | review-request write | required |",
|
|
3511
|
+
"| Feedback reviews | `myte feedback reviews [--status open/terminal/all] [--request-id <id>] --json` (`requests` alias) | `GET /project-assistant/feedback-review-requests` or `GET /project-assistant/feedback-review-requests/<id>` | read | no |",
|
|
3512
|
+
"| Feedback review | `myte feedback review --request-id <id> --action approve/reject/request_changes/cancel [--reason \"...\"] --json` | `POST /project-assistant/feedback-review-requests/<id>/review`, `/request-changes`, or `/cancel` | governed review write | no |",
|
|
3513
|
+
"| Feedback batch review | `myte feedback review --request-ids \"<id1,id2>\" --action approve/reject/request_changes/cancel --json` | `POST /project-assistant/feedback-review-requests/batch-review` | governed review write | no |",
|
|
3514
|
+
"| Feedback move | `myte feedback move --feedback-id <id> --to-state in_progress --reason \"...\" --json` | `POST /project-assistant/feedback/<id>/board-move` | governed write | no |",
|
|
3515
|
+
"| Feedback batch move | `myte feedback move --feedback-ids \"<id1,id2>\" --to-state in_progress --json` | `POST /project-assistant/feedback/batch-board-move` | governed write | no |",
|
|
3516
|
+
"| Feedback comment | `myte feedback comment --feedback-id <id> --body-file ./comment.md --confirm-write --approval-artifact ./comment.md --json` | `POST /project-assistant/feedback/<id>/comments` | comment write | required |",
|
|
3517
|
+
"| Feedback undo | `myte feedback undo --feedback-id <id> --event-id <id> --reason \"...\" --json` | `POST /project-assistant/feedback/<id>/events/<event_id>/undo` | governed write | no |",
|
|
3518
|
+
"| Feedback PRD versions | `myte feedback prd-versions --feedback-id <id> --json` | `GET /project-assistant/feedback/<id>/prd/versions` | read | no |",
|
|
3519
|
+
"| Feedback PRD diff | `myte feedback prd-diff --feedback-id <id> --version-id <id>` | `GET /project-assistant/feedback/<id>/prd/versions/<version_id>/diff` | read | no |",
|
|
3520
|
+
"| Feedback apply | `myte feedback apply --file ./review.yml --json` | `POST /project-assistant/feedback/<id>/refinement/apply` | governed write | no |",
|
|
3521
|
+
"| Create PRD | `myte create-prd ./prd.md --confirm-write --approval-artifact ./prd.md --json` | `POST /project-assistant/create-prd` | PRD write | required |",
|
|
3522
|
+
"| Batch create PRDs | `myte create-prd ./a.md ./b.md --confirm-write --approval-artifact ./approval.md --json` | `POST /project-assistant/create-prds` | PRD write | required |",
|
|
3523
|
+
"| Team update | `myte update-team \"...\" --confirm-write --approval-artifact ./team.md --json` | `POST /project-assistant/project-comment` | project comment | required |",
|
|
3524
|
+
"| Owner update | `myte update-owner --subject \"...\" --body-file ./owner.md --confirm-write --approval-artifact ./owner.md --json` | `POST /project-assistant/update-owner` | owner email | required |",
|
|
3525
|
+
"| Client update | `myte update-client --subject \"...\" --body-file ./client.md --confirm-write --approval-artifact ./client.md --json` | `POST /project-assistant/client-update-drafts` | client draft | required |",
|
|
3526
|
+
"",
|
|
3527
|
+
"## Agent Rules",
|
|
3528
|
+
"",
|
|
3529
|
+
"- For `required` actions, draft the artifact, show it to the user, get explicit approval, then rerun with the approval flags.",
|
|
3530
|
+
"- For `no` actions, do not add approval flags. The API still enforces key binding, project permissions, idempotency, stale-state checks, and route validation.",
|
|
3531
|
+
"- For local draft actions, inspect the generated YAML before submitting or applying it.",
|
|
3532
|
+
"- Use `--print-context` or `--dry-run` where available to inspect payloads without sending a write.",
|
|
3533
|
+
].join("\n"));
|
|
3534
|
+
}
|
|
3535
|
+
|
|
3536
|
+
function writeAgentsMyteApiGuide({ wrapperRoot, outputDir }) {
|
|
3537
|
+
const { targetRoot } = resolveCommandCenterRoots(wrapperRoot, outputDir);
|
|
3538
|
+
const guidePath = path.join(targetRoot, "AgentsMyteAPI.md");
|
|
3539
|
+
writeTextFile(guidePath, buildAgentsMyteApiMarkdown());
|
|
3540
|
+
return guidePath;
|
|
3541
|
+
}
|
|
3542
|
+
|
|
3543
|
+
function pruneLegacyCommandCenterArtifacts(dataRoot, options = {}) {
|
|
3544
|
+
const {
|
|
3545
|
+
bootstrap = false,
|
|
3535
3546
|
qaqc = false,
|
|
3536
3547
|
feedback = false,
|
|
3537
3548
|
missionOps = false,
|
|
@@ -3609,11 +3620,12 @@ function writeBootstrapSnapshot({ snapshot, wrapperRoot, outputDir }) {
|
|
|
3609
3620
|
writeYamlFile(path.join(missionsDir, `${missionPathId}.yml`), mission);
|
|
3610
3621
|
});
|
|
3611
3622
|
|
|
3612
|
-
if (snapshot.project && typeof snapshot.project === "object") {
|
|
3613
|
-
writeYamlFile(path.join(dataRoot, "project.yml"), scrubBootstrapValue(snapshot.project));
|
|
3614
|
-
}
|
|
3615
|
-
|
|
3616
|
-
|
|
3623
|
+
if (snapshot.project && typeof snapshot.project === "object") {
|
|
3624
|
+
writeYamlFile(path.join(dataRoot, "project.yml"), scrubBootstrapValue(snapshot.project));
|
|
3625
|
+
}
|
|
3626
|
+
const agentsMyteApiPath = writeAgentsMyteApiGuide({ wrapperRoot, outputDir });
|
|
3627
|
+
|
|
3628
|
+
const manifest = {
|
|
3617
3629
|
schema_version: snapshot.schema_version || 1,
|
|
3618
3630
|
generated_at: snapshot.generated_at || null,
|
|
3619
3631
|
snapshot_hash: snapshot.snapshot_hash || null,
|
|
@@ -3626,12 +3638,13 @@ function writeBootstrapSnapshot({ snapshot, wrapperRoot, outputDir }) {
|
|
|
3626
3638
|
missions: missions.length,
|
|
3627
3639
|
},
|
|
3628
3640
|
};
|
|
3629
|
-
return {
|
|
3630
|
-
targetRoot,
|
|
3631
|
-
dataRoot,
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
}
|
|
3641
|
+
return {
|
|
3642
|
+
targetRoot,
|
|
3643
|
+
dataRoot,
|
|
3644
|
+
agentsMyteApiPath,
|
|
3645
|
+
manifest,
|
|
3646
|
+
};
|
|
3647
|
+
}
|
|
3635
3648
|
|
|
3636
3649
|
function writeQaqcSnapshot({ snapshot, wrapperRoot, outputDir }) {
|
|
3637
3650
|
const { targetRoot, dataRoot } = resolveCommandCenterRoots(wrapperRoot, outputDir);
|
|
@@ -4514,7 +4527,7 @@ async function fetchSuggestionsSyncSnapshot({ apiBase, key, timeoutMs, actorScop
|
|
|
4514
4527
|
return body.data || {};
|
|
4515
4528
|
}
|
|
4516
4529
|
|
|
4517
|
-
async function createProjectSuggestions({ apiBase, key, timeoutMs, payload, idempotencyKey, clientSessionId
|
|
4530
|
+
async function createProjectSuggestions({ apiBase, key, timeoutMs, payload, idempotencyKey, clientSessionId }) {
|
|
4518
4531
|
return postSuggestionsMutation({
|
|
4519
4532
|
apiBase,
|
|
4520
4533
|
key,
|
|
@@ -4523,11 +4536,10 @@ async function createProjectSuggestions({ apiBase, key, timeoutMs, payload, idem
|
|
|
4523
4536
|
payload,
|
|
4524
4537
|
idempotencyKey,
|
|
4525
4538
|
clientSessionId,
|
|
4526
|
-
writeApproval,
|
|
4527
4539
|
});
|
|
4528
4540
|
}
|
|
4529
4541
|
|
|
4530
|
-
async function reviseProjectSuggestions({ apiBase, key, timeoutMs, payload, idempotencyKey, clientSessionId
|
|
4542
|
+
async function reviseProjectSuggestions({ apiBase, key, timeoutMs, payload, idempotencyKey, clientSessionId }) {
|
|
4531
4543
|
return postSuggestionsMutation({
|
|
4532
4544
|
apiBase,
|
|
4533
4545
|
key,
|
|
@@ -4536,11 +4548,10 @@ async function reviseProjectSuggestions({ apiBase, key, timeoutMs, payload, idem
|
|
|
4536
4548
|
payload,
|
|
4537
4549
|
idempotencyKey,
|
|
4538
4550
|
clientSessionId,
|
|
4539
|
-
writeApproval,
|
|
4540
4551
|
});
|
|
4541
4552
|
}
|
|
4542
4553
|
|
|
4543
|
-
async function reviewProjectSuggestions({ apiBase, key, timeoutMs, payload, idempotencyKey, clientSessionId
|
|
4554
|
+
async function reviewProjectSuggestions({ apiBase, key, timeoutMs, payload, idempotencyKey, clientSessionId }) {
|
|
4544
4555
|
return postSuggestionsMutation({
|
|
4545
4556
|
apiBase,
|
|
4546
4557
|
key,
|
|
@@ -4549,7 +4560,6 @@ async function reviewProjectSuggestions({ apiBase, key, timeoutMs, payload, idem
|
|
|
4549
4560
|
payload,
|
|
4550
4561
|
idempotencyKey,
|
|
4551
4562
|
clientSessionId,
|
|
4552
|
-
writeApproval,
|
|
4553
4563
|
});
|
|
4554
4564
|
}
|
|
4555
4565
|
|
|
@@ -4658,20 +4668,19 @@ async function runCreatePrd(args) {
|
|
|
4658
4668
|
|
|
4659
4669
|
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id);
|
|
4660
4670
|
|
|
4661
|
-
if (payloads.length === 1) {
|
|
4662
|
-
let data;
|
|
4663
|
-
|
|
4664
|
-
if (clientSessionId) payload.client_session_id = clientSessionId;
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
|
|
4671
|
+
if (payloads.length === 1) {
|
|
4672
|
+
let data;
|
|
4673
|
+
let payload = payloads[0];
|
|
4674
|
+
if (clientSessionId) payload.client_session_id = clientSessionId;
|
|
4675
|
+
payload = withWriteApproval(args, payload, {
|
|
4676
|
+
artifactKind: "markdown",
|
|
4677
|
+
targets: [firstNonEmptyString(payload.client_ref, payload.title, "create-prd")],
|
|
4678
|
+
});
|
|
4679
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
4680
|
+
args,
|
|
4681
|
+
operation: "create_prd",
|
|
4668
4682
|
payload,
|
|
4669
4683
|
});
|
|
4670
|
-
const writeApproval = requireWriteApproval(args, payload, {
|
|
4671
|
-
operation: "create_prd",
|
|
4672
|
-
artifactKind: "markdown",
|
|
4673
|
-
targets: prdApprovalTargets(payload),
|
|
4674
|
-
});
|
|
4675
4684
|
try {
|
|
4676
4685
|
data = await postSuggestionsMutation({
|
|
4677
4686
|
apiBase,
|
|
@@ -4681,7 +4690,6 @@ async function runCreatePrd(args) {
|
|
|
4681
4690
|
endpoint: "/project-assistant/create-prd",
|
|
4682
4691
|
idempotencyKey,
|
|
4683
4692
|
clientSessionId,
|
|
4684
|
-
writeApproval,
|
|
4685
4693
|
});
|
|
4686
4694
|
} catch (err) {
|
|
4687
4695
|
if (err?.name === "AbortError") {
|
|
@@ -4723,22 +4731,20 @@ async function runCreatePrd(args) {
|
|
|
4723
4731
|
failed_count: 0,
|
|
4724
4732
|
items: [],
|
|
4725
4733
|
};
|
|
4726
|
-
|
|
4727
|
-
try {
|
|
4728
|
-
|
|
4729
|
-
if (clientSessionId) payload.client_session_id = clientSessionId;
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4734
|
+
|
|
4735
|
+
try {
|
|
4736
|
+
let payload = { items: payloads };
|
|
4737
|
+
if (clientSessionId) payload.client_session_id = clientSessionId;
|
|
4738
|
+
payload = withWriteApproval(args, payload, {
|
|
4739
|
+
artifactKind: "markdown",
|
|
4740
|
+
targets: payloads.map((item, index) => firstNonEmptyString(item.client_ref, item.title, `index:${index}`)),
|
|
4741
|
+
batchCount: payloads.length,
|
|
4742
|
+
});
|
|
4743
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
4744
|
+
args,
|
|
4745
|
+
operation: "create_prds",
|
|
4733
4746
|
payload,
|
|
4734
4747
|
});
|
|
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
4748
|
const data = await postSuggestionsMutation({
|
|
4743
4749
|
apiBase,
|
|
4744
4750
|
key,
|
|
@@ -4747,7 +4753,6 @@ async function runCreatePrd(args) {
|
|
|
4747
4753
|
endpoint: "/project-assistant/create-prds",
|
|
4748
4754
|
idempotencyKey,
|
|
4749
4755
|
clientSessionId,
|
|
4750
|
-
writeApproval,
|
|
4751
4756
|
});
|
|
4752
4757
|
aggregated.project_id = data.project_id || null;
|
|
4753
4758
|
aggregated.created_count = Number(data.created_count || 0);
|
|
@@ -4932,10 +4937,11 @@ async function runBootstrap(args) {
|
|
|
4932
4937
|
return;
|
|
4933
4938
|
}
|
|
4934
4939
|
|
|
4935
|
-
const writeResult = writeBootstrapSnapshot({ snapshot, wrapperRoot, outputDir });
|
|
4936
|
-
summary.data_root = writeResult.dataRoot;
|
|
4937
|
-
|
|
4938
|
-
|
|
4940
|
+
const writeResult = writeBootstrapSnapshot({ snapshot, wrapperRoot, outputDir });
|
|
4941
|
+
summary.data_root = writeResult.dataRoot;
|
|
4942
|
+
summary.agents_myte_api_path = writeResult.agentsMyteApiPath;
|
|
4943
|
+
|
|
4944
|
+
if (includeSuggestions) {
|
|
4939
4945
|
let missionOpsSnapshot;
|
|
4940
4946
|
try {
|
|
4941
4947
|
missionOpsSnapshot = await fetchSuggestionsSyncSnapshot({ apiBase, key, timeoutMs, actorScope });
|
|
@@ -4966,9 +4972,10 @@ async function runBootstrap(args) {
|
|
|
4966
4972
|
console.log(`Output root: ${summary.output_root}`);
|
|
4967
4973
|
console.log(`Configured repos: ${summary.repo_names.join(", ") || "(none)"}`);
|
|
4968
4974
|
console.log(`Found locally: ${summary.local.found.join(", ") || "(none)"}`);
|
|
4969
|
-
if (summary.local.missing.length) console.log(`Missing locally: ${summary.local.missing.join(", ")}`);
|
|
4970
|
-
console.log(`Wrote: phases=${summary.counts.phases}, epics=${summary.counts.epics}, stories=${summary.counts.stories}, missions=${summary.counts.missions}`);
|
|
4971
|
-
if (summary.
|
|
4975
|
+
if (summary.local.missing.length) console.log(`Missing locally: ${summary.local.missing.join(", ")}`);
|
|
4976
|
+
console.log(`Wrote: phases=${summary.counts.phases}, epics=${summary.counts.epics}, stories=${summary.counts.stories}, missions=${summary.counts.missions}`);
|
|
4977
|
+
if (summary.agents_myte_api_path) console.log(`Wrote AgentsMyteAPI: ${summary.agents_myte_api_path}`);
|
|
4978
|
+
if (summary.mission_ops?.included) {
|
|
4972
4979
|
console.log(`Wrote mission ops: total_threads=${summary.mission_ops.total_threads}, actionable_threads=${summary.mission_ops.actionable_threads}`);
|
|
4973
4980
|
} else {
|
|
4974
4981
|
console.log("Skipped mission ops sync.");
|
|
@@ -5304,7 +5311,8 @@ async function runFeedbackValidateOrApply(args, mode) {
|
|
|
5304
5311
|
console.error("Missing MYTE_API_KEY (project key) in environment/.env");
|
|
5305
5312
|
process.exit(1);
|
|
5306
5313
|
}
|
|
5307
|
-
const { absPath, payload } = readFeedbackRefinementArtifact(args);
|
|
5314
|
+
const { absPath, payload: artifactPayload } = readFeedbackRefinementArtifact(args);
|
|
5315
|
+
let payload = artifactPayload;
|
|
5308
5316
|
const feedbackId = firstNonEmptyString(args["feedback-id"], args.feedbackId, args.feedback_id, payload.feedback_id);
|
|
5309
5317
|
if (!feedbackId) {
|
|
5310
5318
|
console.error("Feedback refinement artifact is missing feedback_id.");
|
|
@@ -5314,26 +5322,19 @@ async function runFeedbackValidateOrApply(args, mode) {
|
|
|
5314
5322
|
|
|
5315
5323
|
const timeoutMs = resolveTimeoutMs(args);
|
|
5316
5324
|
const apiBase = resolveApiBase(args);
|
|
5317
|
-
const clientSessionId = firstNonEmptyString(
|
|
5325
|
+
const clientSessionId = firstNonEmptyString(
|
|
5318
5326
|
args["client-session-id"],
|
|
5319
5327
|
args.clientSessionId,
|
|
5320
5328
|
args.client_session_id,
|
|
5321
5329
|
payload.client_session_id
|
|
5322
|
-
);
|
|
5323
|
-
const idempotencyKey = mode === "apply"
|
|
5324
|
-
? resolveProjectMutationIdempotencyKey({
|
|
5325
|
-
args,
|
|
5330
|
+
);
|
|
5331
|
+
const idempotencyKey = mode === "apply"
|
|
5332
|
+
? resolveProjectMutationIdempotencyKey({
|
|
5333
|
+
args,
|
|
5326
5334
|
operation: `feedback_refinement_apply:${feedbackId}`,
|
|
5327
5335
|
payload,
|
|
5328
5336
|
})
|
|
5329
5337
|
: 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
|
|
|
5338
5339
|
let data;
|
|
5339
5340
|
try {
|
|
@@ -5346,7 +5347,6 @@ async function runFeedbackValidateOrApply(args, mode) {
|
|
|
5346
5347
|
payload,
|
|
5347
5348
|
idempotencyKey,
|
|
5348
5349
|
clientSessionId,
|
|
5349
|
-
writeApproval,
|
|
5350
5350
|
});
|
|
5351
5351
|
} catch (err) {
|
|
5352
5352
|
if (args.json) {
|
|
@@ -5458,7 +5458,8 @@ async function runFeedbackSubmit(args) {
|
|
|
5458
5458
|
console.error("Missing MYTE_API_KEY (project key) in environment/.env");
|
|
5459
5459
|
process.exit(1);
|
|
5460
5460
|
}
|
|
5461
|
-
const { absPath, payload } = readFeedbackRefinementArtifact(args);
|
|
5461
|
+
const { absPath, payload: artifactPayload } = readFeedbackRefinementArtifact(args);
|
|
5462
|
+
let payload = artifactPayload;
|
|
5462
5463
|
const feedbackId = firstNonEmptyString(args["feedback-id"], args.feedbackId, args.feedback_id, payload.feedback_id);
|
|
5463
5464
|
if (!feedbackId) {
|
|
5464
5465
|
console.error("Feedback refinement artifact is missing feedback_id.");
|
|
@@ -5466,22 +5467,21 @@ async function runFeedbackSubmit(args) {
|
|
|
5466
5467
|
}
|
|
5467
5468
|
const timeoutMs = resolveTimeoutMs(args);
|
|
5468
5469
|
const apiBase = resolveApiBase(args);
|
|
5469
|
-
const clientSessionId = firstNonEmptyString(
|
|
5470
|
+
const clientSessionId = firstNonEmptyString(
|
|
5470
5471
|
args["client-session-id"],
|
|
5471
5472
|
args.clientSessionId,
|
|
5472
5473
|
args.client_session_id,
|
|
5473
5474
|
payload.client_session_id
|
|
5474
|
-
);
|
|
5475
|
-
|
|
5475
|
+
);
|
|
5476
|
+
payload = withWriteApproval(args, payload, {
|
|
5477
|
+
artifactKind: "yaml",
|
|
5478
|
+
targets: [feedbackId],
|
|
5479
|
+
});
|
|
5480
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
5476
5481
|
args,
|
|
5477
5482
|
operation: `feedback_refinement_request_submit:${feedbackId}`,
|
|
5478
5483
|
payload,
|
|
5479
5484
|
});
|
|
5480
|
-
const writeApproval = requireWriteApproval(args, payload, {
|
|
5481
|
-
operation: `feedback_refinement_request_submit:${feedbackId}`,
|
|
5482
|
-
artifactKind: "yaml",
|
|
5483
|
-
targets: [feedbackId],
|
|
5484
|
-
});
|
|
5485
5485
|
|
|
5486
5486
|
let data;
|
|
5487
5487
|
try {
|
|
@@ -5493,7 +5493,6 @@ async function runFeedbackSubmit(args) {
|
|
|
5493
5493
|
payload,
|
|
5494
5494
|
idempotencyKey,
|
|
5495
5495
|
clientSessionId,
|
|
5496
|
-
writeApproval,
|
|
5497
5496
|
});
|
|
5498
5497
|
} catch (err) {
|
|
5499
5498
|
if (args.json) {
|
|
@@ -5535,25 +5534,25 @@ async function runFeedbackRevise(args) {
|
|
|
5535
5534
|
console.error("Missing --request-id.");
|
|
5536
5535
|
process.exit(1);
|
|
5537
5536
|
}
|
|
5538
|
-
const { absPath, payload } = readFeedbackRefinementArtifact(args);
|
|
5537
|
+
const { absPath, payload: artifactPayload } = readFeedbackRefinementArtifact(args);
|
|
5538
|
+
let payload = artifactPayload;
|
|
5539
5539
|
const timeoutMs = resolveTimeoutMs(args);
|
|
5540
5540
|
const apiBase = resolveApiBase(args);
|
|
5541
|
-
const clientSessionId = firstNonEmptyString(
|
|
5541
|
+
const clientSessionId = firstNonEmptyString(
|
|
5542
5542
|
args["client-session-id"],
|
|
5543
5543
|
args.clientSessionId,
|
|
5544
5544
|
args.client_session_id,
|
|
5545
5545
|
payload.client_session_id
|
|
5546
|
-
);
|
|
5547
|
-
|
|
5546
|
+
);
|
|
5547
|
+
payload = withWriteApproval(args, payload, {
|
|
5548
|
+
artifactKind: "yaml",
|
|
5549
|
+
targets: [requestId],
|
|
5550
|
+
});
|
|
5551
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
5548
5552
|
args,
|
|
5549
5553
|
operation: `feedback_refinement_request_revise:${requestId}`,
|
|
5550
5554
|
payload,
|
|
5551
5555
|
});
|
|
5552
|
-
const writeApproval = requireWriteApproval(args, payload, {
|
|
5553
|
-
operation: `feedback_refinement_request_revise:${requestId}`,
|
|
5554
|
-
artifactKind: "yaml",
|
|
5555
|
-
targets: [requestId],
|
|
5556
|
-
});
|
|
5557
5556
|
|
|
5558
5557
|
let data;
|
|
5559
5558
|
try {
|
|
@@ -5566,7 +5565,6 @@ async function runFeedbackRevise(args) {
|
|
|
5566
5565
|
payload,
|
|
5567
5566
|
idempotencyKey,
|
|
5568
5567
|
clientSessionId,
|
|
5569
|
-
writeApproval,
|
|
5570
5568
|
});
|
|
5571
5569
|
} catch (err) {
|
|
5572
5570
|
if (args.json) {
|
|
@@ -5684,29 +5682,20 @@ async function runFeedbackReviewDecision(args) {
|
|
|
5684
5682
|
process.exit(1);
|
|
5685
5683
|
}
|
|
5686
5684
|
const reason = firstNonEmptyString(args.reason, args["review-note"], args.reviewNote, args.review_note);
|
|
5687
|
-
|
|
5688
|
-
...(isPlainObject(filePayload) && !Array.isArray(filePayload) ? filePayload : {}),
|
|
5689
|
-
items,
|
|
5690
|
-
action,
|
|
5691
|
-
reason: reason || undefined,
|
|
5692
|
-
};
|
|
5693
|
-
const timeoutMs = resolveTimeoutMs(args);
|
|
5694
|
-
const apiBase = resolveApiBase(args);
|
|
5685
|
+
let payload = {
|
|
5686
|
+
...(isPlainObject(filePayload) && !Array.isArray(filePayload) ? filePayload : {}),
|
|
5687
|
+
items,
|
|
5688
|
+
action,
|
|
5689
|
+
reason: reason || undefined,
|
|
5690
|
+
};
|
|
5691
|
+
const timeoutMs = resolveTimeoutMs(args);
|
|
5692
|
+
const apiBase = resolveApiBase(args);
|
|
5695
5693
|
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id, payload.client_session_id);
|
|
5696
5694
|
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
5697
5695
|
args,
|
|
5698
5696
|
operation: `feedback_review_batch:${action}:${items.map((item) => item.request_id || item.id || "").join(",")}`,
|
|
5699
5697
|
payload,
|
|
5700
5698
|
});
|
|
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
5699
|
|
|
5711
5700
|
let data;
|
|
5712
5701
|
try {
|
|
@@ -5717,7 +5706,6 @@ async function runFeedbackReviewDecision(args) {
|
|
|
5717
5706
|
payload,
|
|
5718
5707
|
idempotencyKey,
|
|
5719
5708
|
clientSessionId,
|
|
5720
|
-
writeApproval,
|
|
5721
5709
|
});
|
|
5722
5710
|
} catch (err) {
|
|
5723
5711
|
if (args.json) {
|
|
@@ -5745,8 +5733,8 @@ async function runFeedbackReviewDecision(args) {
|
|
|
5745
5733
|
process.exit(1);
|
|
5746
5734
|
}
|
|
5747
5735
|
|
|
5748
|
-
let payload;
|
|
5749
|
-
try {
|
|
5736
|
+
let payload;
|
|
5737
|
+
try {
|
|
5750
5738
|
payload = filePayload && !Array.isArray(filePayload?.items)
|
|
5751
5739
|
? buildFeedbackReviewDecisionPayload({ ...args, file: "" }, action)
|
|
5752
5740
|
: buildFeedbackReviewDecisionPayload(args, action);
|
|
@@ -5757,9 +5745,9 @@ async function runFeedbackReviewDecision(args) {
|
|
|
5757
5745
|
console.error(err?.message || err);
|
|
5758
5746
|
process.exit(1);
|
|
5759
5747
|
}
|
|
5760
|
-
const endpointAction = action === "request_changes" ? "request-changes" : action === "cancel" ? "cancel" : "review";
|
|
5761
|
-
const timeoutMs = resolveTimeoutMs(args);
|
|
5762
|
-
const apiBase = resolveApiBase(args);
|
|
5748
|
+
const endpointAction = action === "request_changes" ? "request-changes" : action === "cancel" ? "cancel" : "review";
|
|
5749
|
+
const timeoutMs = resolveTimeoutMs(args);
|
|
5750
|
+
const apiBase = resolveApiBase(args);
|
|
5763
5751
|
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id, payload.client_session_id);
|
|
5764
5752
|
const operationAction = action === "request_changes" ? "request_changes" : action;
|
|
5765
5753
|
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
@@ -5767,11 +5755,6 @@ async function runFeedbackReviewDecision(args) {
|
|
|
5767
5755
|
operation: `feedback_review_request_${operationAction}:${requestId}`,
|
|
5768
5756
|
payload,
|
|
5769
5757
|
});
|
|
5770
|
-
const writeApproval = requireWriteApproval(args, payload, {
|
|
5771
|
-
operation: `feedback_review_request_${operationAction}:${requestId}`,
|
|
5772
|
-
artifactKind: "yaml",
|
|
5773
|
-
targets: [requestId],
|
|
5774
|
-
});
|
|
5775
5758
|
|
|
5776
5759
|
let data;
|
|
5777
5760
|
try {
|
|
@@ -5784,7 +5767,6 @@ async function runFeedbackReviewDecision(args) {
|
|
|
5784
5767
|
payload,
|
|
5785
5768
|
idempotencyKey,
|
|
5786
5769
|
clientSessionId,
|
|
5787
|
-
writeApproval,
|
|
5788
5770
|
});
|
|
5789
5771
|
} catch (err) {
|
|
5790
5772
|
if (args.json) {
|
|
@@ -5823,32 +5805,26 @@ async function runFeedbackMove(args) {
|
|
|
5823
5805
|
process.exit(1);
|
|
5824
5806
|
}
|
|
5825
5807
|
const fromState = firstNonEmptyString(args["from-state"], args.fromState, args.from_state) || undefined;
|
|
5826
|
-
|
|
5827
|
-
to_state: toState,
|
|
5828
|
-
reason: firstNonEmptyString(args.reason) || undefined,
|
|
5829
|
-
};
|
|
5808
|
+
let payload = {
|
|
5809
|
+
to_state: toState,
|
|
5810
|
+
reason: firstNonEmptyString(args.reason) || undefined,
|
|
5811
|
+
};
|
|
5830
5812
|
const timeoutMs = resolveTimeoutMs(args);
|
|
5831
5813
|
const apiBase = resolveApiBase(args);
|
|
5832
5814
|
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id);
|
|
5833
5815
|
const isBatch = feedbackIds.length > 1 || Boolean(firstNonEmptyString(args["feedback-ids"], args.feedbackIds, args.feedback_ids));
|
|
5834
|
-
if (isBatch) {
|
|
5835
|
-
payload.feedback_ids = feedbackIds;
|
|
5816
|
+
if (isBatch) {
|
|
5817
|
+
payload.feedback_ids = feedbackIds;
|
|
5836
5818
|
if (fromState) {
|
|
5837
5819
|
payload.from_states = Object.fromEntries(feedbackIds.map((id) => [id, fromState]));
|
|
5838
5820
|
}
|
|
5839
5821
|
const batchId = firstNonEmptyString(args["batch-id"], args.batchId, args.batch_id);
|
|
5840
|
-
if (batchId) payload.batch_id = batchId;
|
|
5841
|
-
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
5842
|
-
args,
|
|
5843
|
-
operation: `feedback_board_batch_move:${toState}:${feedbackIds.join(",")}`,
|
|
5822
|
+
if (batchId) payload.batch_id = batchId;
|
|
5823
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
5824
|
+
args,
|
|
5825
|
+
operation: `feedback_board_batch_move:${toState}:${feedbackIds.join(",")}`,
|
|
5844
5826
|
payload,
|
|
5845
5827
|
});
|
|
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
5828
|
let data;
|
|
5853
5829
|
try {
|
|
5854
5830
|
data = await postFeedbackBatchBoardMutation({
|
|
@@ -5858,7 +5834,6 @@ async function runFeedbackMove(args) {
|
|
|
5858
5834
|
payload,
|
|
5859
5835
|
idempotencyKey,
|
|
5860
5836
|
clientSessionId,
|
|
5861
|
-
writeApproval,
|
|
5862
5837
|
});
|
|
5863
5838
|
} catch (err) {
|
|
5864
5839
|
if (args.json) {
|
|
@@ -5879,18 +5854,13 @@ async function runFeedbackMove(args) {
|
|
|
5879
5854
|
if (postSync?.error) console.error(`Feedback sync warning: ${postSync.error}`);
|
|
5880
5855
|
return;
|
|
5881
5856
|
}
|
|
5882
|
-
|
|
5883
|
-
payload.from_state = fromState;
|
|
5884
|
-
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
5885
|
-
args,
|
|
5886
|
-
operation: `feedback_board_move:${feedbackId}`,
|
|
5857
|
+
|
|
5858
|
+
payload.from_state = fromState;
|
|
5859
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
5860
|
+
args,
|
|
5861
|
+
operation: `feedback_board_move:${feedbackId}`,
|
|
5887
5862
|
payload,
|
|
5888
5863
|
});
|
|
5889
|
-
const writeApproval = requireWriteApproval(args, payload, {
|
|
5890
|
-
operation: `feedback_board_move:${feedbackId}`,
|
|
5891
|
-
artifactKind: "yaml",
|
|
5892
|
-
targets: [feedbackId],
|
|
5893
|
-
});
|
|
5894
5864
|
|
|
5895
5865
|
let data;
|
|
5896
5866
|
try {
|
|
@@ -5903,7 +5873,6 @@ async function runFeedbackMove(args) {
|
|
|
5903
5873
|
payload,
|
|
5904
5874
|
idempotencyKey,
|
|
5905
5875
|
clientSessionId,
|
|
5906
|
-
writeApproval,
|
|
5907
5876
|
});
|
|
5908
5877
|
} catch (err) {
|
|
5909
5878
|
if (args.json) {
|
|
@@ -5944,12 +5913,16 @@ async function runFeedbackComment(args) {
|
|
|
5944
5913
|
process.exit(1);
|
|
5945
5914
|
}
|
|
5946
5915
|
|
|
5947
|
-
|
|
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
|
-
|
|
5916
|
+
let payload = { content };
|
|
5917
|
+
const timeoutMs = resolveTimeoutMs(args);
|
|
5918
|
+
const apiBase = resolveApiBase(args);
|
|
5919
|
+
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id);
|
|
5920
|
+
if (clientSessionId) payload.client_session_id = clientSessionId;
|
|
5921
|
+
payload = withWriteApproval(args, payload, {
|
|
5922
|
+
artifactKind: "markdown",
|
|
5923
|
+
targets: [feedbackId],
|
|
5924
|
+
});
|
|
5925
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
5953
5926
|
args,
|
|
5954
5927
|
operation: `feedback_comment_create:${feedbackId}`,
|
|
5955
5928
|
payload,
|
|
@@ -5960,12 +5933,6 @@ async function runFeedbackComment(args) {
|
|
|
5960
5933
|
return;
|
|
5961
5934
|
}
|
|
5962
5935
|
|
|
5963
|
-
const writeApproval = requireWriteApproval(args, payload, {
|
|
5964
|
-
operation: `feedback_comment_create:${feedbackId}`,
|
|
5965
|
-
artifactKind: "markdown",
|
|
5966
|
-
targets: [feedbackId],
|
|
5967
|
-
});
|
|
5968
|
-
|
|
5969
5936
|
let data;
|
|
5970
5937
|
try {
|
|
5971
5938
|
data = await postFeedbackComment({
|
|
@@ -5976,7 +5943,6 @@ async function runFeedbackComment(args) {
|
|
|
5976
5943
|
payload,
|
|
5977
5944
|
idempotencyKey,
|
|
5978
5945
|
clientSessionId,
|
|
5979
|
-
writeApproval,
|
|
5980
5946
|
});
|
|
5981
5947
|
} catch (err) {
|
|
5982
5948
|
if (args.json) {
|
|
@@ -6025,27 +5991,16 @@ async function runFeedbackUndo(args) {
|
|
|
6025
5991
|
console.error("Missing --event-id.");
|
|
6026
5992
|
process.exit(1);
|
|
6027
5993
|
}
|
|
6028
|
-
|
|
6029
|
-
const timeoutMs = resolveTimeoutMs(args);
|
|
6030
|
-
const apiBase = resolveApiBase(args);
|
|
6031
|
-
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id);
|
|
6032
|
-
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
6033
|
-
args,
|
|
6034
|
-
operation: `feedback_event_undo:${feedbackId}:${eventId}`,
|
|
5994
|
+
let payload = { reason: firstNonEmptyString(args.reason) || undefined };
|
|
5995
|
+
const timeoutMs = resolveTimeoutMs(args);
|
|
5996
|
+
const apiBase = resolveApiBase(args);
|
|
5997
|
+
const clientSessionId = firstNonEmptyString(args["client-session-id"], args.clientSessionId, args.client_session_id);
|
|
5998
|
+
const idempotencyKey = resolveProjectMutationIdempotencyKey({
|
|
5999
|
+
args,
|
|
6000
|
+
operation: `feedback_event_undo:${feedbackId}:${eventId}`,
|
|
6035
6001
|
payload,
|
|
6036
6002
|
});
|
|
6037
6003
|
|
|
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
6004
|
let data;
|
|
6050
6005
|
try {
|
|
6051
6006
|
data = await postFeedbackBoardMutation({
|
|
@@ -6057,7 +6012,6 @@ async function runFeedbackUndo(args) {
|
|
|
6057
6012
|
payload,
|
|
6058
6013
|
idempotencyKey,
|
|
6059
6014
|
clientSessionId,
|
|
6060
|
-
writeApproval,
|
|
6061
6015
|
});
|
|
6062
6016
|
} catch (err) {
|
|
6063
6017
|
if (args.json) {
|
|
@@ -6343,14 +6297,22 @@ async function buildSuggestionsMutationContext(args, mode) {
|
|
|
6343
6297
|
if (clientSessionId && !payload.client_session_id) {
|
|
6344
6298
|
payload.client_session_id = clientSessionId;
|
|
6345
6299
|
}
|
|
6346
|
-
if (mode === "create") {
|
|
6347
|
-
validateSuggestionsCreatePayload(payload);
|
|
6348
|
-
} else if (mode === "revise") {
|
|
6349
|
-
validateSuggestionsRevisePayload(payload);
|
|
6350
|
-
}
|
|
6351
|
-
const
|
|
6352
|
-
|
|
6353
|
-
|
|
6300
|
+
if (mode === "create") {
|
|
6301
|
+
validateSuggestionsCreatePayload(payload);
|
|
6302
|
+
} else if (mode === "revise") {
|
|
6303
|
+
validateSuggestionsRevisePayload(payload);
|
|
6304
|
+
}
|
|
6305
|
+
const items = Array.isArray(payload?.items) ? payload.items : [];
|
|
6306
|
+
if (mode === "create" || mode === "revise") {
|
|
6307
|
+
payload = withWriteApproval(args, payload, {
|
|
6308
|
+
artifactKind: "yaml",
|
|
6309
|
+
targets: suggestionWriteTargets(items),
|
|
6310
|
+
batchCount: items.length > 1 ? items.length : null,
|
|
6311
|
+
});
|
|
6312
|
+
}
|
|
6313
|
+
const idempotencyKey = resolveSuggestionsIdempotencyKey({
|
|
6314
|
+
args,
|
|
6315
|
+
mode,
|
|
6354
6316
|
actorScope,
|
|
6355
6317
|
payload,
|
|
6356
6318
|
});
|
|
@@ -6436,14 +6398,6 @@ async function runSuggestionsCreate(args) {
|
|
|
6436
6398
|
return;
|
|
6437
6399
|
}
|
|
6438
6400
|
|
|
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
6401
|
let data;
|
|
6448
6402
|
try {
|
|
6449
6403
|
data = await createProjectSuggestions({
|
|
@@ -6453,7 +6407,6 @@ async function runSuggestionsCreate(args) {
|
|
|
6453
6407
|
payload: context.payload,
|
|
6454
6408
|
idempotencyKey: context.idempotencyKey,
|
|
6455
6409
|
clientSessionId: context.clientSessionId,
|
|
6456
|
-
writeApproval,
|
|
6457
6410
|
});
|
|
6458
6411
|
} catch (err) {
|
|
6459
6412
|
console.error("Suggestions create failed:", err?.message || err);
|
|
@@ -6530,14 +6483,6 @@ async function runSuggestionsRevise(args) {
|
|
|
6530
6483
|
return;
|
|
6531
6484
|
}
|
|
6532
6485
|
|
|
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
6486
|
let data;
|
|
6542
6487
|
try {
|
|
6543
6488
|
data = await reviseProjectSuggestions({
|
|
@@ -6547,7 +6492,6 @@ async function runSuggestionsRevise(args) {
|
|
|
6547
6492
|
payload: context.payload,
|
|
6548
6493
|
idempotencyKey: context.idempotencyKey,
|
|
6549
6494
|
clientSessionId: context.clientSessionId,
|
|
6550
|
-
writeApproval,
|
|
6551
6495
|
});
|
|
6552
6496
|
} catch (err) {
|
|
6553
6497
|
console.error("Suggestions revise failed:", err?.message || err);
|
|
@@ -6622,14 +6566,6 @@ async function runSuggestionsReview(args) {
|
|
|
6622
6566
|
return;
|
|
6623
6567
|
}
|
|
6624
6568
|
|
|
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
6569
|
let data;
|
|
6634
6570
|
try {
|
|
6635
6571
|
data = await reviewProjectSuggestions({
|
|
@@ -6639,7 +6575,6 @@ async function runSuggestionsReview(args) {
|
|
|
6639
6575
|
payload: context.payload,
|
|
6640
6576
|
idempotencyKey: context.idempotencyKey,
|
|
6641
6577
|
clientSessionId: context.clientSessionId,
|
|
6642
|
-
writeApproval,
|
|
6643
6578
|
});
|
|
6644
6579
|
} catch (err) {
|
|
6645
6580
|
console.error("Suggestions review failed:", err?.message || err);
|