scripts/review-artifacts.mjs
scripts/review-artifacts.mjsBrowse 8 files
1,442 tokens
6,135 bytes
Token encoding: o200k_base
Snapshot fac8604
← Back to SKILL.md
1const REVIEW_ACTIONS_VERSION = 2;2const TARGET_KIND_VALUES = new Set([3 'review_thread',4 'review_comment',5 'pull_request_review',6 'issue_comment',7]);8const DECISION_VALUES = new Set([9 'triage_pending',10 'will_address',11 'defer',12 'out_of_scope',13 'already_fixed',14 'not_actionable',15 'wont_address',16]);17const STATUS_VALUES = new Set(['pending', 'in_progress', 'done']);18 19function isNonEmptyString(value) {20 return typeof value === 'string' && value.length > 0;21}22 23function assertReviewActionsV1(reviewActions) {24 if (typeof reviewActions !== 'object' || reviewActions === null) {25 throw new TypeError('review-actions must be an object');26 }27 if (reviewActions.version !== REVIEW_ACTIONS_VERSION) {28 throw new TypeError(`review-actions version must be ${REVIEW_ACTIONS_VERSION}`);29 }30 if (typeof reviewActions.pr !== 'object' || reviewActions.pr === null) {31 throw new TypeError('review-actions pr must be an object');32 }33 if (!isNonEmptyString(reviewActions.pr.url)) {34 throw new TypeError('review-actions pr.url must be a non-empty string');35 }36 if (typeof reviewActions.reviewState !== 'object' || reviewActions.reviewState === null) {37 throw new TypeError('review-actions reviewState must be an object');38 }39 if (!isNonEmptyString(reviewActions.reviewState.path)) {40 throw new TypeError('review-actions reviewState.path must be a non-empty string');41 }42 if (!isNonEmptyString(reviewActions.reviewState.fetchedAt)) {43 throw new TypeError('review-actions reviewState.fetchedAt must be a non-empty string');44 }45 if (reviewActions.reviewState.version !== 2) {46 throw new TypeError('review-actions reviewState.version must be 2');47 }48 if (!Array.isArray(reviewActions.actions)) {49 throw new TypeError('review-actions actions must be an array');50 }51 52 const seenActionIds = new Set();53 for (let index = 0; index < reviewActions.actions.length; index += 1) {54 const action = reviewActions.actions[index];55 const pointer = `review-actions actions[${index}]`;56 if (!isNonEmptyString(action?.actionId)) {57 throw new TypeError(`${pointer}.actionId must be a non-empty string`);58 }59 if (seenActionIds.has(action.actionId)) {60 throw new TypeError(`${pointer}.actionId must be unique`);61 }62 seenActionIds.add(action.actionId);63 if (typeof action?.target !== 'object' || action.target === null) {64 throw new TypeError(`${pointer}.target must be an object`);65 }66 if (!TARGET_KIND_VALUES.has(action.target.kind)) {67 throw new TypeError(`${pointer}.target.kind must be a supported value`);68 }69 if (!isNonEmptyString(action.target.nodeId)) {70 throw new TypeError(`${pointer}.target.nodeId must be a non-empty string`);71 }72 if (!DECISION_VALUES.has(action?.decision)) {73 throw new TypeError(`${pointer}.decision must be a supported value`);74 }75 if (action.decision === 'wont_address' && !isNonEmptyString(action?.rationale)) {76 throw new TypeError(77 `${pointer}.rationale must be a non-empty string when decision is wont_address`,78 );79 }80 if (action.decision !== 'triage_pending' && !isNonEmptyString(action?.summary)) {81 throw new TypeError(`${pointer}.summary must be a non-empty string once triaged`);82 }83 if (84 action.summary !== null &&85 action.summary !== undefined &&86 typeof action.summary !== 'string'87 ) {88 throw new TypeError(`${pointer}.summary must be a string or null`);89 }90 if (91 action.rationale !== null &&92 action.rationale !== undefined &&93 typeof action.rationale !== 'string'94 ) {95 throw new TypeError(`${pointer}.rationale must be a string or null`);96 }97 if (98 action.linearIssue !== null &&99 action.linearIssue !== undefined &&100 typeof action.linearIssue !== 'string'101 ) {102 throw new TypeError(`${pointer}.linearIssue must be a string or null`);103 }104 if (action.decision === 'defer' && !isNonEmptyString(action?.linearIssue)) {105 throw new TypeError(`${pointer}.linearIssue must be set when decision is defer`);106 }107 if (!Array.isArray(action?.targetFiles)) {108 throw new TypeError(`${pointer}.targetFiles must be an array`);109 }110 for (let i = 0; i < action.targetFiles.length; i += 1) {111 if (!isNonEmptyString(action.targetFiles[i])) {112 throw new TypeError(`${pointer}.targetFiles[${i}] must be a non-empty string`);113 }114 }115 if (116 action.acceptance !== null &&117 action.acceptance !== undefined &&118 typeof action.acceptance !== 'string'119 ) {120 throw new TypeError(`${pointer}.acceptance must be a string or null`);121 }122 if (123 action.status === 'done' &&124 (typeof action.done !== 'object' ||125 action.done === null ||126 !isNonEmptyString(action.done.doneAt))127 ) {128 throw new TypeError(`${pointer}.done.doneAt must be present when status is done`);129 }130 if (action.done !== null && action.done !== undefined) {131 if (typeof action.done !== 'object') {132 throw new TypeError(`${pointer}.done must be an object or null`);133 }134 if (!isNonEmptyString(action.done.doneAt)) {135 throw new TypeError(`${pointer}.done.doneAt must be a non-empty string`);136 }137 if (138 action.done.summary !== null &&139 action.done.summary !== undefined &&140 typeof action.done.summary !== 'string'141 ) {142 throw new TypeError(`${pointer}.done.summary must be a string or null`);143 }144 if (!Array.isArray(action.done.commits)) {145 throw new TypeError(`${pointer}.done.commits must be an array`);146 }147 for (let commitIndex = 0; commitIndex < action.done.commits.length; commitIndex += 1) {148 if (!isNonEmptyString(action.done.commits[commitIndex])) {149 throw new TypeError(`${pointer}.done.commits[${commitIndex}] must be a non-empty string`);150 }151 }152 }153 if (!STATUS_VALUES.has(action?.status)) {154 throw new TypeError(`${pointer}.status must be one of pending|in_progress|done`);155 }156 }157 return reviewActions;158}159 160export { assertReviewActionsV1, REVIEW_ACTIONS_VERSION };161