@jonit-dev/night-watch-cli 1.8.12-beta.9 → 1.8.13
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/dist/cli.js +351 -118
- package/dist/commands/audit.d.ts.map +1 -1
- package/dist/commands/audit.js +5 -1
- package/dist/commands/audit.js.map +1 -1
- package/dist/commands/board.d.ts.map +1 -1
- package/dist/commands/board.js +2 -0
- package/dist/commands/board.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +1 -0
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/run.d.ts +14 -1
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +97 -40
- package/dist/commands/run.js.map +1 -1
- package/dist/scripts/night-watch-audit-cron.sh +11 -1
- package/dist/scripts/night-watch-cron.sh +4 -2
- package/dist/scripts/night-watch-merger-cron.sh +177 -32
- package/dist/scripts/night-watch-pr-reviewer-cron.sh +107 -2
- package/dist/templates/audit.md +64 -30
- package/dist/templates/night-watch-audit.md +71 -30
- package/dist/templates/night-watch-pr-reviewer.md +7 -6
- package/dist/templates/pr-reviewer.md +7 -6
- package/dist/web/assets/index-CL3Q-KB4.css +1 -0
- package/dist/web/assets/index-FDOCfjkP.js +442 -0
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -290,13 +290,14 @@ var init_job_registry = __esm({
|
|
|
290
290
|
{
|
|
291
291
|
id: "audit",
|
|
292
292
|
name: "Auditor",
|
|
293
|
-
description: "Performs
|
|
293
|
+
description: "Performs consolidated architecture and code quality audits",
|
|
294
294
|
cliCommand: "audit",
|
|
295
295
|
logName: "audit",
|
|
296
296
|
lockSuffix: "-audit.lock",
|
|
297
297
|
queuePriority: 10,
|
|
298
298
|
envPrefix: "NW_AUDIT",
|
|
299
299
|
extraFields: [
|
|
300
|
+
{ name: "createIssues", type: "boolean", defaultValue: false },
|
|
300
301
|
{
|
|
301
302
|
name: "targetColumn",
|
|
302
303
|
type: "enum",
|
|
@@ -305,9 +306,10 @@ var init_job_registry = __esm({
|
|
|
305
306
|
}
|
|
306
307
|
],
|
|
307
308
|
defaultConfig: {
|
|
308
|
-
enabled:
|
|
309
|
+
enabled: false,
|
|
309
310
|
schedule: "50 3 * * 1",
|
|
310
311
|
maxRuntime: 1800,
|
|
312
|
+
createIssues: false,
|
|
311
313
|
targetColumn: "Draft"
|
|
312
314
|
}
|
|
313
315
|
},
|
|
@@ -390,7 +392,7 @@ function resolveProviderBucketKey(provider, providerEnv) {
|
|
|
390
392
|
return `claude-proxy:${baseUrl}`;
|
|
391
393
|
}
|
|
392
394
|
}
|
|
393
|
-
var DEFAULT_DEFAULT_BRANCH, DEFAULT_PRD_DIR, DEFAULT_SUMMARY_WINDOW_HOURS, DEFAULT_MAX_RUNTIME, DEFAULT_REVIEWER_MAX_RUNTIME, DEFAULT_CRON_SCHEDULE, DEFAULT_REVIEWER_SCHEDULE, DEFAULT_CRON_SCHEDULE_OFFSET, DEFAULT_MAX_RETRIES, DEFAULT_REVIEWER_MAX_RETRIES, DEFAULT_REVIEWER_RETRY_DELAY, DEFAULT_REVIEWER_MAX_PRS_PER_RUN, DEFAULT_FEEDBACK, DEFAULT_BRANCH_PREFIX, DEFAULT_BRANCH_PATTERNS, DEFAULT_MIN_REVIEW_SCORE, DEFAULT_MAX_LOG_SIZE, DEFAULT_PROVIDER, DEFAULT_EXECUTOR_ENABLED, DEFAULT_REVIEWER_ENABLED, DEFAULT_PROVIDER_ENV, DEFAULT_FALLBACK_ON_RATE_LIMIT, DEFAULT_CLAUDE_MODEL, DEFAULT_PRIMARY_FALLBACK_MODEL, DEFAULT_SECONDARY_FALLBACK_MODEL, VALID_CLAUDE_MODELS, CLAUDE_MODEL_IDS, DEFAULT_NOTIFICATIONS, DEFAULT_PRD_PRIORITY, DEFAULT_SLICER_SCHEDULE, DEFAULT_SLICER_MAX_RUNTIME, DEFAULT_ROADMAP_SCANNER, DEFAULT_TEMPLATES_DIR, DEFAULT_BOARD_PROVIDER, DEFAULT_LOCAL_BOARD_INFO, DEFAULT_AUTO_MERGE, DEFAULT_AUTO_MERGE_METHOD, VALID_MERGE_METHODS, DEFAULT_QA_ENABLED, DEFAULT_QA_SCHEDULE, DEFAULT_QA_MAX_RUNTIME, DEFAULT_QA_ARTIFACTS, DEFAULT_QA_SKIP_LABEL, DEFAULT_QA_AUTO_INSTALL_PLAYWRIGHT, DEFAULT_QA_VALIDATED_LABEL, DEFAULT_QA, QA_LOG_NAME, DEFAULT_AUDIT_ENABLED, DEFAULT_AUDIT_SCHEDULE, DEFAULT_AUDIT_MAX_RUNTIME, DEFAULT_AUDIT_TARGET_COLUMN, DEFAULT_AUDIT, DEFAULT_ANALYTICS_ENABLED, DEFAULT_ANALYTICS_SCHEDULE, DEFAULT_ANALYTICS_MAX_RUNTIME, DEFAULT_ANALYTICS_LOOKBACK_DAYS, DEFAULT_ANALYTICS_TARGET_COLUMN, DEFAULT_ANALYTICS_PROMPT, DEFAULT_ANALYTICS, DEFAULT_PR_RESOLVER_ENABLED, DEFAULT_PR_RESOLVER_SCHEDULE, DEFAULT_PR_RESOLVER_MAX_RUNTIME, DEFAULT_PR_RESOLVER_MAX_PRS_PER_RUN, DEFAULT_PR_RESOLVER_PER_PR_TIMEOUT, DEFAULT_PR_RESOLVER_AI_CONFLICT_RESOLUTION, DEFAULT_PR_RESOLVER_AI_REVIEW_RESOLUTION, DEFAULT_PR_RESOLVER_READY_LABEL, DEFAULT_PR_RESOLVER, DEFAULT_MERGER_ENABLED, DEFAULT_MERGER_SCHEDULE, DEFAULT_MERGER_MAX_RUNTIME, DEFAULT_MERGER_MERGE_METHOD, DEFAULT_MERGER_MIN_REVIEW_SCORE, DEFAULT_MERGER_REBASE_BEFORE_MERGE, DEFAULT_MERGER_MAX_PRS_PER_RUN, DEFAULT_MERGER, MERGER_LOG_NAME, AUDIT_LOG_NAME, PLANNER_LOG_NAME, ANALYTICS_LOG_NAME, PR_RESOLVER_LOG_NAME, VALID_PROVIDERS, VALID_JOB_TYPES, DEFAULT_JOB_PROVIDERS, DEFAULT_PROVIDER_SCHEDULE_OVERRIDES, DEFAULT_WEBHOOK_TRIGGER_SECRET_ENV, DEFAULT_WEBHOOK_TRIGGER_MAX_SKEW_SECONDS, DEFAULT_WEBHOOK_TRIGGERS, BUILT_IN_PRESETS, BUILT_IN_PRESET_IDS, PROVIDER_COMMANDS, CONFIG_FILE_NAME, LOCK_FILE_PREFIX, LOG_DIR, CLAIM_FILE_EXTENSION, EXECUTOR_LOG_NAME, REVIEWER_LOG_NAME, EXECUTOR_LOG_FILE, REVIEWER_LOG_FILE, LOG_FILE_NAMES, GLOBAL_CONFIG_DIR, REGISTRY_FILE_NAME, HISTORY_FILE_NAME, PRD_STATES_FILE_NAME, STATE_DB_FILE_NAME, GLOBAL_NOTIFICATIONS_FILE_NAME, MAX_HISTORY_RECORDS_PER_PRD, DEFAULT_QUEUE_ENABLED, DEFAULT_QUEUE_MODE, DEFAULT_QUEUE_MAX_CONCURRENCY, DEFAULT_QUEUE_MAX_WAIT_TIME, DEFAULT_QUEUE_PRIORITY, DEFAULT_QUEUE, DEFAULT_SCHEDULING_PRIORITY;
|
|
395
|
+
var DEFAULT_DEFAULT_BRANCH, DEFAULT_PRD_DIR, DEFAULT_SUMMARY_WINDOW_HOURS, DEFAULT_MAX_RUNTIME, DEFAULT_REVIEWER_MAX_RUNTIME, DEFAULT_CRON_SCHEDULE, DEFAULT_REVIEWER_SCHEDULE, DEFAULT_CRON_SCHEDULE_OFFSET, DEFAULT_MAX_RETRIES, DEFAULT_REVIEWER_MAX_RETRIES, DEFAULT_REVIEWER_RETRY_DELAY, DEFAULT_REVIEWER_MAX_PRS_PER_RUN, DEFAULT_FEEDBACK, DEFAULT_BRANCH_PREFIX, DEFAULT_BRANCH_PATTERNS, DEFAULT_MIN_REVIEW_SCORE, DEFAULT_MAX_LOG_SIZE, DEFAULT_PROVIDER, DEFAULT_EXECUTOR_ENABLED, DEFAULT_REVIEWER_ENABLED, DEFAULT_PROVIDER_ENV, DEFAULT_FALLBACK_ON_RATE_LIMIT, DEFAULT_CLAUDE_MODEL, DEFAULT_PRIMARY_FALLBACK_MODEL, DEFAULT_SECONDARY_FALLBACK_MODEL, VALID_CLAUDE_MODELS, CLAUDE_MODEL_IDS, DEFAULT_NOTIFICATIONS, DEFAULT_PRD_PRIORITY, DEFAULT_SLICER_SCHEDULE, DEFAULT_SLICER_MAX_RUNTIME, DEFAULT_ROADMAP_SCANNER, DEFAULT_TEMPLATES_DIR, DEFAULT_BOARD_PROVIDER, DEFAULT_LOCAL_BOARD_INFO, DEFAULT_AUTO_MERGE, DEFAULT_AUTO_MERGE_METHOD, VALID_MERGE_METHODS, DEFAULT_QA_ENABLED, DEFAULT_QA_SCHEDULE, DEFAULT_QA_MAX_RUNTIME, DEFAULT_QA_ARTIFACTS, DEFAULT_QA_SKIP_LABEL, DEFAULT_QA_AUTO_INSTALL_PLAYWRIGHT, DEFAULT_QA_VALIDATED_LABEL, DEFAULT_QA, QA_LOG_NAME, DEFAULT_AUDIT_ENABLED, DEFAULT_AUDIT_SCHEDULE, DEFAULT_AUDIT_MAX_RUNTIME, DEFAULT_AUDIT_CREATE_ISSUES, DEFAULT_AUDIT_TARGET_COLUMN, DEFAULT_AUDIT, DEFAULT_ANALYTICS_ENABLED, DEFAULT_ANALYTICS_SCHEDULE, DEFAULT_ANALYTICS_MAX_RUNTIME, DEFAULT_ANALYTICS_LOOKBACK_DAYS, DEFAULT_ANALYTICS_TARGET_COLUMN, DEFAULT_ANALYTICS_PROMPT, DEFAULT_ANALYTICS, DEFAULT_PR_RESOLVER_ENABLED, DEFAULT_PR_RESOLVER_SCHEDULE, DEFAULT_PR_RESOLVER_MAX_RUNTIME, DEFAULT_PR_RESOLVER_MAX_PRS_PER_RUN, DEFAULT_PR_RESOLVER_PER_PR_TIMEOUT, DEFAULT_PR_RESOLVER_AI_CONFLICT_RESOLUTION, DEFAULT_PR_RESOLVER_AI_REVIEW_RESOLUTION, DEFAULT_PR_RESOLVER_READY_LABEL, DEFAULT_PR_RESOLVER, DEFAULT_MERGER_ENABLED, DEFAULT_MERGER_SCHEDULE, DEFAULT_MERGER_MAX_RUNTIME, DEFAULT_MERGER_MERGE_METHOD, DEFAULT_MERGER_MIN_REVIEW_SCORE, DEFAULT_MERGER_REBASE_BEFORE_MERGE, DEFAULT_MERGER_MAX_PRS_PER_RUN, DEFAULT_MERGER, MERGER_LOG_NAME, AUDIT_LOG_NAME, PLANNER_LOG_NAME, ANALYTICS_LOG_NAME, PR_RESOLVER_LOG_NAME, VALID_PROVIDERS, VALID_JOB_TYPES, DEFAULT_JOB_PROVIDERS, DEFAULT_PROVIDER_SCHEDULE_OVERRIDES, DEFAULT_WEBHOOK_TRIGGER_SECRET_ENV, DEFAULT_WEBHOOK_TRIGGER_MAX_SKEW_SECONDS, DEFAULT_WEBHOOK_TRIGGERS, BUILT_IN_PRESETS, BUILT_IN_PRESET_IDS, PROVIDER_COMMANDS, CONFIG_FILE_NAME, LOCK_FILE_PREFIX, LOG_DIR, CLAIM_FILE_EXTENSION, EXECUTOR_LOG_NAME, REVIEWER_LOG_NAME, EXECUTOR_LOG_FILE, REVIEWER_LOG_FILE, LOG_FILE_NAMES, GLOBAL_CONFIG_DIR, REGISTRY_FILE_NAME, HISTORY_FILE_NAME, PRD_STATES_FILE_NAME, STATE_DB_FILE_NAME, GLOBAL_NOTIFICATIONS_FILE_NAME, MAX_HISTORY_RECORDS_PER_PRD, DEFAULT_QUEUE_ENABLED, DEFAULT_QUEUE_MODE, DEFAULT_QUEUE_MAX_CONCURRENCY, DEFAULT_QUEUE_MAX_WAIT_TIME, DEFAULT_QUEUE_PRIORITY, DEFAULT_QUEUE, DEFAULT_SCHEDULING_PRIORITY;
|
|
394
396
|
var init_constants = __esm({
|
|
395
397
|
"../core/dist/constants.js"() {
|
|
396
398
|
"use strict";
|
|
@@ -471,14 +473,16 @@ var init_constants = __esm({
|
|
|
471
473
|
validatedLabel: DEFAULT_QA_VALIDATED_LABEL
|
|
472
474
|
};
|
|
473
475
|
QA_LOG_NAME = "night-watch-qa";
|
|
474
|
-
DEFAULT_AUDIT_ENABLED =
|
|
476
|
+
DEFAULT_AUDIT_ENABLED = false;
|
|
475
477
|
DEFAULT_AUDIT_SCHEDULE = "50 3 * * 1";
|
|
476
478
|
DEFAULT_AUDIT_MAX_RUNTIME = 1800;
|
|
479
|
+
DEFAULT_AUDIT_CREATE_ISSUES = false;
|
|
477
480
|
DEFAULT_AUDIT_TARGET_COLUMN = "Draft";
|
|
478
481
|
DEFAULT_AUDIT = {
|
|
479
482
|
enabled: DEFAULT_AUDIT_ENABLED,
|
|
480
483
|
schedule: DEFAULT_AUDIT_SCHEDULE,
|
|
481
484
|
maxRuntime: DEFAULT_AUDIT_MAX_RUNTIME,
|
|
485
|
+
createIssues: DEFAULT_AUDIT_CREATE_ISSUES,
|
|
482
486
|
targetColumn: DEFAULT_AUDIT_TARGET_COLUMN
|
|
483
487
|
};
|
|
484
488
|
DEFAULT_ANALYTICS_ENABLED = false;
|
|
@@ -816,6 +820,9 @@ function normalizeConfig(rawConfig) {
|
|
|
816
820
|
if (typeof rawBoardProvider.projectNumber === "number") {
|
|
817
821
|
bp.projectNumber = rawBoardProvider.projectNumber;
|
|
818
822
|
}
|
|
823
|
+
if (typeof rawBoardProvider.projectTitle === "string") {
|
|
824
|
+
bp.projectTitle = rawBoardProvider.projectTitle;
|
|
825
|
+
}
|
|
819
826
|
if (typeof rawBoardProvider.repo === "string") {
|
|
820
827
|
bp.repo = rawBoardProvider.repo;
|
|
821
828
|
}
|
|
@@ -867,7 +874,11 @@ function normalizeConfig(rawConfig) {
|
|
|
867
874
|
continue;
|
|
868
875
|
const rawJob = readObject2(rawConfig[jobId]);
|
|
869
876
|
if (rawJob) {
|
|
870
|
-
|
|
877
|
+
const normalizedJob = normalizeJobConfig(rawJob, jobDef);
|
|
878
|
+
if (jobId === "audit" && rawJob.createIssues === void 0 && rawJob.targetColumn !== void 0) {
|
|
879
|
+
normalizedJob.createIssues = true;
|
|
880
|
+
}
|
|
881
|
+
normalized[jobId] = normalizedJob;
|
|
871
882
|
}
|
|
872
883
|
}
|
|
873
884
|
const prResolverDef = getJobDef("pr-resolver");
|
|
@@ -2926,12 +2937,18 @@ var init_github_projects_base = __esm({
|
|
|
2926
2937
|
if (this.cachedOwner && this.cachedRepositoryId)
|
|
2927
2938
|
return this.cachedOwner;
|
|
2928
2939
|
const { owner, name } = await this.getRepoParts();
|
|
2929
|
-
const data = await graphql(`
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2940
|
+
const data = await graphql(`
|
|
2941
|
+
query ResolveRepoOwner($owner: String!, $name: String!) {
|
|
2942
|
+
repository(owner: $owner, name: $name) {
|
|
2943
|
+
id
|
|
2944
|
+
owner {
|
|
2945
|
+
__typename
|
|
2946
|
+
id
|
|
2947
|
+
login
|
|
2948
|
+
}
|
|
2949
|
+
}
|
|
2933
2950
|
}
|
|
2934
|
-
|
|
2951
|
+
`, { owner, name }, this.cwd);
|
|
2935
2952
|
if (!data.repository)
|
|
2936
2953
|
throw new Error(`Repository ${owner}/${name} not found.`);
|
|
2937
2954
|
const ownerNode = data.repository.owner;
|
|
@@ -2967,24 +2984,49 @@ var init_github_projects_base = __esm({
|
|
|
2967
2984
|
}
|
|
2968
2985
|
return null;
|
|
2969
2986
|
}
|
|
2987
|
+
assertProjectUsable(projectNode) {
|
|
2988
|
+
if (projectNode.closed === true) {
|
|
2989
|
+
throw new Error(`Configured GitHub Project #${projectNode.number} is closed: "${projectNode.title}". Update boardProvider.projectNumber to an open Night Watch board or run \`night-watch board setup\`.`);
|
|
2990
|
+
}
|
|
2991
|
+
const expectedTitle = this.config.projectTitle?.trim();
|
|
2992
|
+
if (expectedTitle && projectNode.title !== expectedTitle) {
|
|
2993
|
+
throw new Error(`Configured GitHub Project #${projectNode.number} title mismatch. Expected "${expectedTitle}", got "${projectNode.title}". Update boardProvider.projectNumber/projectTitle or run \`night-watch board setup\`.`);
|
|
2994
|
+
}
|
|
2995
|
+
}
|
|
2970
2996
|
/** Try user query first, fall back to org query. */
|
|
2971
2997
|
async fetchProjectNode(login, projectNumber) {
|
|
2972
2998
|
try {
|
|
2973
|
-
const userData = await graphql(`
|
|
2974
|
-
|
|
2975
|
-
|
|
2999
|
+
const userData = await graphql(`
|
|
3000
|
+
query GetProject($login: String!, $number: Int!) {
|
|
3001
|
+
user(login: $login) {
|
|
3002
|
+
projectV2(number: $number) {
|
|
3003
|
+
id
|
|
3004
|
+
number
|
|
3005
|
+
title
|
|
3006
|
+
url
|
|
3007
|
+
closed
|
|
3008
|
+
}
|
|
3009
|
+
}
|
|
2976
3010
|
}
|
|
2977
|
-
|
|
3011
|
+
`, { login, number: projectNumber }, this.cwd);
|
|
2978
3012
|
if (userData.user?.projectV2)
|
|
2979
3013
|
return userData.user.projectV2;
|
|
2980
3014
|
} catch {
|
|
2981
3015
|
}
|
|
2982
3016
|
try {
|
|
2983
|
-
const orgData = await graphql(`
|
|
2984
|
-
|
|
2985
|
-
|
|
3017
|
+
const orgData = await graphql(`
|
|
3018
|
+
query GetOrgProject($login: String!, $number: Int!) {
|
|
3019
|
+
organization(login: $login) {
|
|
3020
|
+
projectV2(number: $number) {
|
|
3021
|
+
id
|
|
3022
|
+
number
|
|
3023
|
+
title
|
|
3024
|
+
url
|
|
3025
|
+
closed
|
|
3026
|
+
}
|
|
3027
|
+
}
|
|
2986
3028
|
}
|
|
2987
|
-
|
|
3029
|
+
`, { login, number: projectNumber }, this.cwd);
|
|
2988
3030
|
if (orgData.organization?.projectV2)
|
|
2989
3031
|
return orgData.organization.projectV2;
|
|
2990
3032
|
} catch {
|
|
@@ -2993,13 +3035,21 @@ var init_github_projects_base = __esm({
|
|
|
2993
3035
|
}
|
|
2994
3036
|
async ensureProjectCache() {
|
|
2995
3037
|
if (this.cachedProjectId !== null && this.cachedFieldId !== null && this.cachedOptionIds.size > 0) {
|
|
2996
|
-
return {
|
|
3038
|
+
return {
|
|
3039
|
+
projectId: this.cachedProjectId,
|
|
3040
|
+
fieldId: this.cachedFieldId,
|
|
3041
|
+
optionIds: this.cachedOptionIds
|
|
3042
|
+
};
|
|
2997
3043
|
}
|
|
2998
3044
|
if (this.cachedProjectId !== null) {
|
|
2999
3045
|
const statusField2 = await this.fetchStatusField(this.cachedProjectId);
|
|
3000
3046
|
this.cachedFieldId = statusField2.fieldId;
|
|
3001
3047
|
this.cachedOptionIds = statusField2.optionIds;
|
|
3002
|
-
return {
|
|
3048
|
+
return {
|
|
3049
|
+
projectId: this.cachedProjectId,
|
|
3050
|
+
fieldId: this.cachedFieldId,
|
|
3051
|
+
optionIds: this.cachedOptionIds
|
|
3052
|
+
};
|
|
3003
3053
|
}
|
|
3004
3054
|
const projectNumber = this.config.projectNumber;
|
|
3005
3055
|
if (!projectNumber) {
|
|
@@ -3009,28 +3059,38 @@ var init_github_projects_base = __esm({
|
|
|
3009
3059
|
if (!projectNode) {
|
|
3010
3060
|
throw new Error(`GitHub Project #${projectNumber} not found for repository owner "${await this.getRepoOwnerLogin()}".`);
|
|
3011
3061
|
}
|
|
3062
|
+
this.assertProjectUsable(projectNode);
|
|
3012
3063
|
this.cachedProjectId = projectNode.id;
|
|
3013
3064
|
const statusField = await this.fetchStatusField(projectNode.id);
|
|
3014
3065
|
this.cachedFieldId = statusField.fieldId;
|
|
3015
3066
|
this.cachedOptionIds = statusField.optionIds;
|
|
3016
|
-
return {
|
|
3067
|
+
return {
|
|
3068
|
+
projectId: this.cachedProjectId,
|
|
3069
|
+
fieldId: this.cachedFieldId,
|
|
3070
|
+
optionIds: this.cachedOptionIds
|
|
3071
|
+
};
|
|
3017
3072
|
}
|
|
3018
3073
|
// -------------------------------------------------------------------------
|
|
3019
3074
|
// Status field management
|
|
3020
3075
|
// -------------------------------------------------------------------------
|
|
3021
3076
|
async fetchStatusField(projectId) {
|
|
3022
|
-
const fieldData = await graphql(`
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3077
|
+
const fieldData = await graphql(`
|
|
3078
|
+
query GetStatusField($projectId: ID!) {
|
|
3079
|
+
node(id: $projectId) {
|
|
3080
|
+
... on ProjectV2 {
|
|
3081
|
+
field(name: "Status") {
|
|
3082
|
+
... on ProjectV2SingleSelectField {
|
|
3083
|
+
id
|
|
3084
|
+
options {
|
|
3085
|
+
id
|
|
3086
|
+
name
|
|
3087
|
+
}
|
|
3088
|
+
}
|
|
3029
3089
|
}
|
|
3030
3090
|
}
|
|
3031
3091
|
}
|
|
3032
3092
|
}
|
|
3033
|
-
|
|
3093
|
+
`, { projectId }, this.cwd);
|
|
3034
3094
|
const field = fieldData.node?.field;
|
|
3035
3095
|
if (!field) {
|
|
3036
3096
|
throw new Error(`Status field not found on project ${projectId}. Run \`night-watch board setup\` to create it.`);
|
|
@@ -3038,18 +3098,23 @@ var init_github_projects_base = __esm({
|
|
|
3038
3098
|
return { fieldId: field.id, optionIds: new Map(field.options.map((o) => [o.name, o.id])) };
|
|
3039
3099
|
}
|
|
3040
3100
|
async ensureStatusColumns(projectId) {
|
|
3041
|
-
const fieldData = await graphql(`
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3101
|
+
const fieldData = await graphql(`
|
|
3102
|
+
query GetStatusField($projectId: ID!) {
|
|
3103
|
+
node(id: $projectId) {
|
|
3104
|
+
... on ProjectV2 {
|
|
3105
|
+
field(name: "Status") {
|
|
3106
|
+
... on ProjectV2SingleSelectField {
|
|
3107
|
+
id
|
|
3108
|
+
options {
|
|
3109
|
+
id
|
|
3110
|
+
name
|
|
3111
|
+
}
|
|
3112
|
+
}
|
|
3048
3113
|
}
|
|
3049
3114
|
}
|
|
3050
3115
|
}
|
|
3051
3116
|
}
|
|
3052
|
-
|
|
3117
|
+
`, { projectId }, this.cwd);
|
|
3053
3118
|
const field = fieldData.node?.field;
|
|
3054
3119
|
if (!field)
|
|
3055
3120
|
return;
|
|
@@ -3057,31 +3122,47 @@ var init_github_projects_base = __esm({
|
|
|
3057
3122
|
const required = ["Draft", "Ready", "In Progress", "Review", "Done"];
|
|
3058
3123
|
if (required.every((n) => existing.has(n)))
|
|
3059
3124
|
return;
|
|
3060
|
-
await graphql(`
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3125
|
+
await graphql(`
|
|
3126
|
+
mutation UpdateField($fieldId: ID!) {
|
|
3127
|
+
updateProjectV2Field(
|
|
3128
|
+
input: {
|
|
3129
|
+
fieldId: $fieldId
|
|
3130
|
+
singleSelectOptions: [
|
|
3131
|
+
{ name: "Draft", color: GRAY, description: "" }
|
|
3132
|
+
{ name: "Ready", color: BLUE, description: "" }
|
|
3133
|
+
{ name: "In Progress", color: YELLOW, description: "" }
|
|
3134
|
+
{ name: "Review", color: ORANGE, description: "" }
|
|
3135
|
+
{ name: "Done", color: GREEN, description: "" }
|
|
3136
|
+
]
|
|
3137
|
+
}
|
|
3138
|
+
) {
|
|
3139
|
+
projectV2Field {
|
|
3140
|
+
... on ProjectV2SingleSelectField {
|
|
3141
|
+
id
|
|
3142
|
+
options {
|
|
3143
|
+
id
|
|
3144
|
+
name
|
|
3145
|
+
}
|
|
3146
|
+
}
|
|
3147
|
+
}
|
|
3073
3148
|
}
|
|
3074
3149
|
}
|
|
3075
|
-
|
|
3150
|
+
`, { fieldId: field.id }, this.cwd);
|
|
3076
3151
|
}
|
|
3077
3152
|
async linkProjectToRepository(projectId) {
|
|
3078
3153
|
const repositoryId = await this.getRepositoryNodeId();
|
|
3079
3154
|
try {
|
|
3080
|
-
await graphql(`
|
|
3081
|
-
|
|
3082
|
-
|
|
3155
|
+
await graphql(`
|
|
3156
|
+
mutation LinkProjectToRepository($projectId: ID!, $repositoryId: ID!) {
|
|
3157
|
+
linkProjectV2ToRepository(
|
|
3158
|
+
input: { projectId: $projectId, repositoryId: $repositoryId }
|
|
3159
|
+
) {
|
|
3160
|
+
repository {
|
|
3161
|
+
id
|
|
3162
|
+
}
|
|
3163
|
+
}
|
|
3083
3164
|
}
|
|
3084
|
-
|
|
3165
|
+
`, { projectId, repositoryId }, this.cwd);
|
|
3085
3166
|
} catch (err) {
|
|
3086
3167
|
const message = err instanceof Error ? err.message : String(err);
|
|
3087
3168
|
if (message.toLowerCase().includes("already") && message.toLowerCase().includes("project"))
|
|
@@ -3162,16 +3243,22 @@ var init_github_projects_base = __esm({
|
|
|
3162
3243
|
};
|
|
3163
3244
|
}
|
|
3164
3245
|
async setItemStatus(projectId, itemId, fieldId, optionId) {
|
|
3165
|
-
await graphql(`
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3246
|
+
await graphql(`
|
|
3247
|
+
mutation UpdateItemField($projectId: ID!, $itemId: ID!, $fieldId: ID!, $optionId: String!) {
|
|
3248
|
+
updateProjectV2ItemFieldValue(
|
|
3249
|
+
input: {
|
|
3250
|
+
projectId: $projectId
|
|
3251
|
+
itemId: $itemId
|
|
3252
|
+
fieldId: $fieldId
|
|
3253
|
+
value: { singleSelectOptionId: $optionId }
|
|
3254
|
+
}
|
|
3255
|
+
) {
|
|
3256
|
+
projectV2Item {
|
|
3257
|
+
id
|
|
3258
|
+
}
|
|
3259
|
+
}
|
|
3173
3260
|
}
|
|
3174
|
-
|
|
3261
|
+
`, { projectId, itemId, fieldId, optionId }, this.cwd);
|
|
3175
3262
|
}
|
|
3176
3263
|
// -------------------------------------------------------------------------
|
|
3177
3264
|
// Project listing
|
|
@@ -3179,19 +3266,39 @@ var init_github_projects_base = __esm({
|
|
|
3179
3266
|
async findExistingProject(owner, title) {
|
|
3180
3267
|
try {
|
|
3181
3268
|
if (owner.type === "User") {
|
|
3182
|
-
const data2 = await graphql(`
|
|
3183
|
-
|
|
3184
|
-
|
|
3269
|
+
const data2 = await graphql(`
|
|
3270
|
+
query ListUserProjects($login: String!) {
|
|
3271
|
+
user(login: $login) {
|
|
3272
|
+
projectsV2(first: 50) {
|
|
3273
|
+
nodes {
|
|
3274
|
+
id
|
|
3275
|
+
number
|
|
3276
|
+
title
|
|
3277
|
+
url
|
|
3278
|
+
closed
|
|
3279
|
+
}
|
|
3280
|
+
}
|
|
3281
|
+
}
|
|
3185
3282
|
}
|
|
3186
|
-
|
|
3187
|
-
return data2.user?.projectsV2.nodes.find((p) => p.title === title) ?? null;
|
|
3283
|
+
`, { login: owner.login }, this.cwd);
|
|
3284
|
+
return data2.user?.projectsV2.nodes.find((p) => p.title === title && p.closed !== true) ?? null;
|
|
3188
3285
|
}
|
|
3189
|
-
const data = await graphql(`
|
|
3190
|
-
|
|
3191
|
-
|
|
3286
|
+
const data = await graphql(`
|
|
3287
|
+
query ListOrgProjects($login: String!) {
|
|
3288
|
+
organization(login: $login) {
|
|
3289
|
+
projectsV2(first: 50) {
|
|
3290
|
+
nodes {
|
|
3291
|
+
id
|
|
3292
|
+
number
|
|
3293
|
+
title
|
|
3294
|
+
url
|
|
3295
|
+
closed
|
|
3296
|
+
}
|
|
3297
|
+
}
|
|
3298
|
+
}
|
|
3192
3299
|
}
|
|
3193
|
-
|
|
3194
|
-
return data.organization?.projectsV2.nodes.find((p) => p.title === title) ?? null;
|
|
3300
|
+
`, { login: owner.login }, this.cwd);
|
|
3301
|
+
return data.organization?.projectsV2.nodes.find((p) => p.title === title && p.closed !== true) ?? null;
|
|
3195
3302
|
} catch {
|
|
3196
3303
|
return null;
|
|
3197
3304
|
}
|
|
@@ -3224,7 +3331,16 @@ var init_github_projects = __esm({
|
|
|
3224
3331
|
async createRepositoryIssue(repo, input) {
|
|
3225
3332
|
const requestedLabels = input.labels ?? [];
|
|
3226
3333
|
const buildIssueArgs = (labels) => {
|
|
3227
|
-
const args = [
|
|
3334
|
+
const args = [
|
|
3335
|
+
"issue",
|
|
3336
|
+
"create",
|
|
3337
|
+
"--title",
|
|
3338
|
+
input.title,
|
|
3339
|
+
"--body",
|
|
3340
|
+
input.body,
|
|
3341
|
+
"--repo",
|
|
3342
|
+
repo
|
|
3343
|
+
];
|
|
3228
3344
|
if (labels.length > 0) {
|
|
3229
3345
|
args.push("--label", labels.join(","));
|
|
3230
3346
|
}
|
|
@@ -3330,6 +3446,11 @@ var init_github_projects = __esm({
|
|
|
3330
3446
|
const node = await this.resolveProjectNode(projectNumber);
|
|
3331
3447
|
if (!node)
|
|
3332
3448
|
return null;
|
|
3449
|
+
if (node.closed === true)
|
|
3450
|
+
return null;
|
|
3451
|
+
if (this.config.projectTitle?.trim() && node.title !== this.config.projectTitle.trim()) {
|
|
3452
|
+
return null;
|
|
3453
|
+
}
|
|
3333
3454
|
return { id: node.id, number: node.number, title: node.title, url: node.url };
|
|
3334
3455
|
} catch {
|
|
3335
3456
|
return null;
|
|
@@ -5977,12 +6098,19 @@ function formatDiscordPayload(ctx) {
|
|
|
5977
6098
|
function formatTelegramPayload(ctx) {
|
|
5978
6099
|
const emoji = getEventEmoji(ctx.event);
|
|
5979
6100
|
const title = ctx.event === "run_succeeded" ? "PR Opened" : getEventTitle(ctx.event);
|
|
5980
|
-
if (ctx.prUrl
|
|
6101
|
+
if (ctx.prUrl || ctx.prTitle || ctx.prNumber !== void 0) {
|
|
5981
6102
|
const lines = [];
|
|
6103
|
+
const prLabelParts = ["PR"];
|
|
6104
|
+
if (ctx.prNumber !== void 0) {
|
|
6105
|
+
prLabelParts.push(`#${ctx.prNumber}`);
|
|
6106
|
+
}
|
|
6107
|
+
const prLabel = ctx.prTitle ? `${prLabelParts.join(" ")}: ${ctx.prTitle}` : prLabelParts.join(" ");
|
|
5982
6108
|
lines.push(`*${escapeMarkdownV2(emoji + " " + title)}*`);
|
|
5983
6109
|
lines.push("");
|
|
5984
|
-
lines.push(`${escapeMarkdownV2("\u{1F4CB}")} *${escapeMarkdownV2(
|
|
5985
|
-
|
|
6110
|
+
lines.push(`${escapeMarkdownV2("\u{1F4CB}")} *${escapeMarkdownV2(prLabel)}*`);
|
|
6111
|
+
if (ctx.prUrl) {
|
|
6112
|
+
lines.push(`${escapeMarkdownV2("\u{1F517}")} ${escapeMarkdownV2(ctx.prUrl)}`);
|
|
6113
|
+
}
|
|
5986
6114
|
if (ctx.prBody && ctx.prBody.trim().length > 0) {
|
|
5987
6115
|
const summary = extractSummary(ctx.prBody);
|
|
5988
6116
|
if (summary) {
|
|
@@ -6030,7 +6158,16 @@ function formatTelegramPayload(ctx) {
|
|
|
6030
6158
|
}
|
|
6031
6159
|
}
|
|
6032
6160
|
lines.push("");
|
|
6033
|
-
lines.push(escapeMarkdownV2(
|
|
6161
|
+
lines.push(escapeMarkdownV2("\u2699\uFE0F Meta"));
|
|
6162
|
+
lines.push(escapeMarkdownV2(`Project: ${ctx.projectName}`));
|
|
6163
|
+
lines.push(escapeMarkdownV2(`Provider: ${ctx.provider}`));
|
|
6164
|
+
lines.push(escapeMarkdownV2(`Exit code: ${ctx.exitCode}`));
|
|
6165
|
+
if (ctx.prdName) {
|
|
6166
|
+
lines.push(escapeMarkdownV2(`PRD: ${ctx.prdName}`));
|
|
6167
|
+
}
|
|
6168
|
+
if (ctx.branchName) {
|
|
6169
|
+
lines.push(escapeMarkdownV2(`Branch: ${ctx.branchName}`));
|
|
6170
|
+
}
|
|
6034
6171
|
return {
|
|
6035
6172
|
text: lines.join("\n"),
|
|
6036
6173
|
parse_mode: "MarkdownV2"
|
|
@@ -8651,6 +8788,16 @@ function buildIssueBody(finding) {
|
|
|
8651
8788
|
async function syncAuditFindingsToBoard(config, projectDir) {
|
|
8652
8789
|
const findings = loadAuditFindings(projectDir);
|
|
8653
8790
|
const targetColumn = config.audit.targetColumn;
|
|
8791
|
+
if (!config.audit.createIssues) {
|
|
8792
|
+
return {
|
|
8793
|
+
status: "skipped",
|
|
8794
|
+
findingsCount: findings.length,
|
|
8795
|
+
issuesCreated: 0,
|
|
8796
|
+
issuesFailed: 0,
|
|
8797
|
+
targetColumn: null,
|
|
8798
|
+
summary: "audit board issue creation is disabled"
|
|
8799
|
+
};
|
|
8800
|
+
}
|
|
8654
8801
|
if (findings.length === 0) {
|
|
8655
8802
|
return {
|
|
8656
8803
|
status: "skipped",
|
|
@@ -9597,6 +9744,7 @@ __export(dist_exports, {
|
|
|
9597
9744
|
DEFAULT_ANALYTICS_SCHEDULE: () => DEFAULT_ANALYTICS_SCHEDULE,
|
|
9598
9745
|
DEFAULT_ANALYTICS_TARGET_COLUMN: () => DEFAULT_ANALYTICS_TARGET_COLUMN,
|
|
9599
9746
|
DEFAULT_AUDIT: () => DEFAULT_AUDIT,
|
|
9747
|
+
DEFAULT_AUDIT_CREATE_ISSUES: () => DEFAULT_AUDIT_CREATE_ISSUES,
|
|
9600
9748
|
DEFAULT_AUDIT_ENABLED: () => DEFAULT_AUDIT_ENABLED,
|
|
9601
9749
|
DEFAULT_AUDIT_MAX_RUNTIME: () => DEFAULT_AUDIT_MAX_RUNTIME,
|
|
9602
9750
|
DEFAULT_AUDIT_SCHEDULE: () => DEFAULT_AUDIT_SCHEDULE,
|
|
@@ -10643,7 +10791,8 @@ function initCommand(program2) {
|
|
|
10643
10791
|
rawConfig.boardProvider = {
|
|
10644
10792
|
enabled: true,
|
|
10645
10793
|
provider: "github",
|
|
10646
|
-
projectNumber: board.number
|
|
10794
|
+
projectNumber: board.number,
|
|
10795
|
+
projectTitle: board.title
|
|
10647
10796
|
};
|
|
10648
10797
|
fs23.writeFileSync(configPath, JSON.stringify(rawConfig, null, 2) + "\n");
|
|
10649
10798
|
boardSetupStatus = `Created (#${board.number})`;
|
|
@@ -10888,6 +11037,27 @@ function resolveRunNotificationEvent(exitCode, scriptStatus) {
|
|
|
10888
11037
|
}
|
|
10889
11038
|
return null;
|
|
10890
11039
|
}
|
|
11040
|
+
function extractPrUrlFromOutput(output) {
|
|
11041
|
+
if (!output) {
|
|
11042
|
+
return void 0;
|
|
11043
|
+
}
|
|
11044
|
+
const matches = Array.from(
|
|
11045
|
+
output.matchAll(/https:\/\/github\.com\/[^\s)]+\/pull\/\d+/g),
|
|
11046
|
+
(match) => match[0]
|
|
11047
|
+
);
|
|
11048
|
+
return matches.at(-1);
|
|
11049
|
+
}
|
|
11050
|
+
function extractResultValueFromOutput(output, key) {
|
|
11051
|
+
if (!output) {
|
|
11052
|
+
return void 0;
|
|
11053
|
+
}
|
|
11054
|
+
const escapedKey = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
11055
|
+
const regex = new RegExp(`\\b${escapedKey}=([^\\s|]+)`, "g");
|
|
11056
|
+
const matches = Array.from(output.matchAll(regex), (match) => match[1]).filter(
|
|
11057
|
+
(value) => value !== void 0 && value.length > 0
|
|
11058
|
+
);
|
|
11059
|
+
return matches.at(-1);
|
|
11060
|
+
}
|
|
10891
11061
|
function shouldAttemptCrossProjectFallback(options, scriptStatus) {
|
|
10892
11062
|
if (options.crossProjectFallback !== true) {
|
|
10893
11063
|
return false;
|
|
@@ -10903,6 +11073,71 @@ function shouldAttemptCrossProjectFallback(options, scriptStatus) {
|
|
|
10903
11073
|
}
|
|
10904
11074
|
return scriptStatus === "skip_no_eligible_prd";
|
|
10905
11075
|
}
|
|
11076
|
+
function parsePrNumberFromUrl(prUrl) {
|
|
11077
|
+
const match = prUrl?.match(/\/pull\/(\d+)(?:\b|[/?#])/);
|
|
11078
|
+
if (!match?.[1]) {
|
|
11079
|
+
return void 0;
|
|
11080
|
+
}
|
|
11081
|
+
const parsed = parseInt(match[1], 10);
|
|
11082
|
+
return Number.isNaN(parsed) ? void 0 : parsed;
|
|
11083
|
+
}
|
|
11084
|
+
function getRunPrMetadata(scriptResult, rawOutput) {
|
|
11085
|
+
const prUrl = scriptResult?.data.pr_url ?? extractPrUrlFromOutput(rawOutput);
|
|
11086
|
+
const branchName = scriptResult?.data.branch ?? extractResultValueFromOutput(rawOutput, "branch");
|
|
11087
|
+
const prNumber = parsePrNumberFromUrl(prUrl) ?? (scriptResult?.data.pr_number ? parseInt(scriptResult.data.pr_number, 10) : void 0);
|
|
11088
|
+
return {
|
|
11089
|
+
prUrl,
|
|
11090
|
+
branchName,
|
|
11091
|
+
prNumber: prNumber !== void 0 && !Number.isNaN(prNumber) ? prNumber : void 0
|
|
11092
|
+
};
|
|
11093
|
+
}
|
|
11094
|
+
function fetchRunPrDetails(config, projectDir, metadata) {
|
|
11095
|
+
if (metadata.prNumber !== void 0) {
|
|
11096
|
+
const details = fetchPrDetailsByNumber(metadata.prNumber, projectDir);
|
|
11097
|
+
if (details) {
|
|
11098
|
+
return details;
|
|
11099
|
+
}
|
|
11100
|
+
}
|
|
11101
|
+
if (metadata.prUrl) {
|
|
11102
|
+
const details = fetchPrDetailsForBranch(metadata.prUrl, projectDir);
|
|
11103
|
+
if (details) {
|
|
11104
|
+
return details;
|
|
11105
|
+
}
|
|
11106
|
+
}
|
|
11107
|
+
if (metadata.branchName) {
|
|
11108
|
+
const details = fetchPrDetailsForBranch(metadata.branchName, projectDir);
|
|
11109
|
+
if (details) {
|
|
11110
|
+
return details;
|
|
11111
|
+
}
|
|
11112
|
+
}
|
|
11113
|
+
return fetchPrDetails(config.branchPrefix, projectDir);
|
|
11114
|
+
}
|
|
11115
|
+
function buildRunNotificationContext(config, projectDir, event, exitCode, scriptResult, prDetails, rawOutput) {
|
|
11116
|
+
const metadata = getRunPrMetadata(scriptResult, rawOutput);
|
|
11117
|
+
const timeoutDuration = event === "run_timeout" ? config.maxRuntime : void 0;
|
|
11118
|
+
const checkpointValue = scriptResult?.data.checkpoint;
|
|
11119
|
+
const checkpointStatus = checkpointValue === "created" || checkpointValue === "available" || checkpointValue === "none" ? checkpointValue : void 0;
|
|
11120
|
+
return {
|
|
11121
|
+
event,
|
|
11122
|
+
projectName: path23.basename(projectDir),
|
|
11123
|
+
exitCode,
|
|
11124
|
+
provider: config.provider,
|
|
11125
|
+
prdName: scriptResult?.data.prd ?? extractResultValueFromOutput(rawOutput, "prd"),
|
|
11126
|
+
branchName: metadata.branchName,
|
|
11127
|
+
duration: timeoutDuration,
|
|
11128
|
+
scriptStatus: scriptResult?.status,
|
|
11129
|
+
failureReason: scriptResult?.data.reason,
|
|
11130
|
+
failureDetail: scriptResult?.data.detail,
|
|
11131
|
+
checkpointStatus,
|
|
11132
|
+
prUrl: prDetails?.url || metadata.prUrl,
|
|
11133
|
+
prTitle: prDetails?.title,
|
|
11134
|
+
prBody: prDetails?.body,
|
|
11135
|
+
prNumber: prDetails?.number ?? metadata.prNumber,
|
|
11136
|
+
filesChanged: prDetails?.changedFiles,
|
|
11137
|
+
additions: prDetails?.additions,
|
|
11138
|
+
deletions: prDetails?.deletions
|
|
11139
|
+
};
|
|
11140
|
+
}
|
|
10906
11141
|
function getCrossProjectFallbackCandidates(currentProjectDir) {
|
|
10907
11142
|
const current = path23.resolve(currentProjectDir);
|
|
10908
11143
|
const { valid, invalid } = validateRegistry();
|
|
@@ -10911,7 +11146,7 @@ function getCrossProjectFallbackCandidates(currentProjectDir) {
|
|
|
10911
11146
|
}
|
|
10912
11147
|
return valid.filter((entry) => path23.resolve(entry.path) !== current);
|
|
10913
11148
|
}
|
|
10914
|
-
async function sendRunCompletionNotifications(config, projectDir, options, exitCode, scriptResult) {
|
|
11149
|
+
async function sendRunCompletionNotifications(config, projectDir, options, exitCode, scriptResult, rawOutput) {
|
|
10915
11150
|
if (isRateLimitFallbackTriggered(scriptResult?.data)) {
|
|
10916
11151
|
const nonTelegramWebhooks = (config.notifications?.webhooks ?? []).filter(
|
|
10917
11152
|
(wh) => wh.type !== "telegram"
|
|
@@ -10935,42 +11170,18 @@ async function sendRunCompletionNotifications(config, projectDir, options, exitC
|
|
|
10935
11170
|
const event = resolveRunNotificationEvent(exitCode, scriptResult?.status);
|
|
10936
11171
|
let prDetails = null;
|
|
10937
11172
|
if (event === "run_succeeded") {
|
|
10938
|
-
|
|
10939
|
-
const branch = scriptResult?.data.branch;
|
|
10940
|
-
if (prUrl) {
|
|
10941
|
-
prDetails = fetchPrDetailsForBranch(prUrl, projectDir);
|
|
10942
|
-
}
|
|
10943
|
-
if (!prDetails && branch) {
|
|
10944
|
-
prDetails = fetchPrDetailsForBranch(branch, projectDir);
|
|
10945
|
-
}
|
|
10946
|
-
if (!prDetails) {
|
|
10947
|
-
prDetails = fetchPrDetails(config.branchPrefix, projectDir);
|
|
10948
|
-
}
|
|
11173
|
+
prDetails = fetchRunPrDetails(config, projectDir, getRunPrMetadata(scriptResult, rawOutput));
|
|
10949
11174
|
}
|
|
10950
11175
|
if (event) {
|
|
10951
|
-
const
|
|
10952
|
-
|
|
10953
|
-
|
|
10954
|
-
const _ctx = {
|
|
11176
|
+
const _ctx = buildRunNotificationContext(
|
|
11177
|
+
config,
|
|
11178
|
+
projectDir,
|
|
10955
11179
|
event,
|
|
10956
|
-
projectName: path23.basename(projectDir),
|
|
10957
11180
|
exitCode,
|
|
10958
|
-
|
|
10959
|
-
|
|
10960
|
-
|
|
10961
|
-
|
|
10962
|
-
scriptStatus: scriptResult?.status,
|
|
10963
|
-
failureReason: scriptResult?.data.reason,
|
|
10964
|
-
failureDetail: scriptResult?.data.detail,
|
|
10965
|
-
checkpointStatus,
|
|
10966
|
-
prUrl: prDetails?.url,
|
|
10967
|
-
prTitle: prDetails?.title,
|
|
10968
|
-
prBody: prDetails?.body,
|
|
10969
|
-
prNumber: prDetails?.number,
|
|
10970
|
-
filesChanged: prDetails?.changedFiles,
|
|
10971
|
-
additions: prDetails?.additions,
|
|
10972
|
-
deletions: prDetails?.deletions
|
|
10973
|
-
};
|
|
11181
|
+
scriptResult,
|
|
11182
|
+
prDetails,
|
|
11183
|
+
rawOutput
|
|
11184
|
+
);
|
|
10974
11185
|
await sendNotifications(config, _ctx);
|
|
10975
11186
|
} else if (!options.dryRun) {
|
|
10976
11187
|
info("Skipping completion notification (no actionable run result)");
|
|
@@ -11021,7 +11232,9 @@ ${stderr}`);
|
|
|
11021
11232
|
candidate.path,
|
|
11022
11233
|
options,
|
|
11023
11234
|
exitCode,
|
|
11024
|
-
scriptResult
|
|
11235
|
+
scriptResult,
|
|
11236
|
+
`${stdout}
|
|
11237
|
+
${stderr}`
|
|
11025
11238
|
);
|
|
11026
11239
|
}
|
|
11027
11240
|
if (exitCode !== 0) {
|
|
@@ -11363,7 +11576,15 @@ ${stderr}`);
|
|
|
11363
11576
|
});
|
|
11364
11577
|
} catch {
|
|
11365
11578
|
}
|
|
11366
|
-
await sendRunCompletionNotifications(
|
|
11579
|
+
await sendRunCompletionNotifications(
|
|
11580
|
+
config,
|
|
11581
|
+
projectDir,
|
|
11582
|
+
options,
|
|
11583
|
+
exitCode,
|
|
11584
|
+
scriptResult,
|
|
11585
|
+
`${stdout}
|
|
11586
|
+
${stderr}`
|
|
11587
|
+
);
|
|
11367
11588
|
}
|
|
11368
11589
|
if (shouldAttemptCrossProjectFallback(options, scriptResult?.status)) {
|
|
11369
11590
|
const executedFallback = await runCrossProjectFallback(projectDir, options);
|
|
@@ -11973,6 +12194,7 @@ import * as path26 from "path";
|
|
|
11973
12194
|
function buildEnvVars4(config, options) {
|
|
11974
12195
|
const env = buildBaseEnvVars(config, "audit", options.dryRun);
|
|
11975
12196
|
env.NW_AUDIT_MAX_RUNTIME = String(config.audit.maxRuntime);
|
|
12197
|
+
env.NW_AUDIT_CREATE_ISSUES = config.audit.createIssues ? "1" : "0";
|
|
11976
12198
|
env.NW_CLAUDE_MODEL_ID = CLAUDE_MODEL_IDS[config.primaryFallbackModel ?? config.claudeModel ?? "sonnet"];
|
|
11977
12199
|
const telegramWebhooks = getTelegramStatusWebhooks(config);
|
|
11978
12200
|
if (telegramWebhooks.length > 0) {
|
|
@@ -12012,7 +12234,10 @@ function auditCommand(program2) {
|
|
|
12012
12234
|
configTable.push(["Provider", auditProvider]);
|
|
12013
12235
|
configTable.push(["Provider CLI", PROVIDER_COMMANDS[auditProvider]]);
|
|
12014
12236
|
configTable.push(["Max Runtime", `${config.audit.maxRuntime}s`]);
|
|
12015
|
-
configTable.push(["
|
|
12237
|
+
configTable.push(["Create Board Issues", config.audit.createIssues ? "yes" : "no"]);
|
|
12238
|
+
if (config.audit.createIssues) {
|
|
12239
|
+
configTable.push(["Target Column", config.audit.targetColumn]);
|
|
12240
|
+
}
|
|
12016
12241
|
configTable.push(["Report File", path26.join(projectDir, "logs", "audit-report.md")]);
|
|
12017
12242
|
console.log(configTable.toString());
|
|
12018
12243
|
header("Provider Invocation");
|
|
@@ -16626,6 +16851,9 @@ function validateConfigChanges(changes, currentConfig) {
|
|
|
16626
16851
|
if (audit.maxRuntime !== void 0 && (typeof audit.maxRuntime !== "number" || audit.maxRuntime < 60)) {
|
|
16627
16852
|
return "audit.maxRuntime must be a number >= 60";
|
|
16628
16853
|
}
|
|
16854
|
+
if (audit.createIssues !== void 0 && typeof audit.createIssues !== "boolean") {
|
|
16855
|
+
return "audit.createIssues must be a boolean";
|
|
16856
|
+
}
|
|
16629
16857
|
if (audit.targetColumn !== void 0 && !BOARD_COLUMNS.includes(audit.targetColumn)) {
|
|
16630
16858
|
return `audit.targetColumn must be one of: ${BOARD_COLUMNS.join(", ")}`;
|
|
16631
16859
|
}
|
|
@@ -16695,6 +16923,9 @@ function validateConfigChanges(changes, currentConfig) {
|
|
|
16695
16923
|
if (changes.boardProvider.projectNumber !== void 0 && (typeof changes.boardProvider.projectNumber !== "number" || !Number.isInteger(changes.boardProvider.projectNumber) || changes.boardProvider.projectNumber <= 0)) {
|
|
16696
16924
|
return "boardProvider.projectNumber must be an integer > 0";
|
|
16697
16925
|
}
|
|
16926
|
+
if (changes.boardProvider.projectTitle !== void 0 && (typeof changes.boardProvider.projectTitle !== "string" || changes.boardProvider.projectTitle.trim().length === 0)) {
|
|
16927
|
+
return "boardProvider.projectTitle must be a non-empty string";
|
|
16928
|
+
}
|
|
16698
16929
|
if (changes.boardProvider.repo !== void 0 && (typeof changes.boardProvider.repo !== "string" || changes.boardProvider.repo.trim().length === 0)) {
|
|
16699
16930
|
return "boardProvider.repo must be a non-empty string";
|
|
16700
16931
|
}
|
|
@@ -19245,7 +19476,8 @@ async function ensureBoardConfigured(config, cwd, provider, options) {
|
|
|
19245
19476
|
...config.boardProvider,
|
|
19246
19477
|
enabled: config.boardProvider?.enabled ?? true,
|
|
19247
19478
|
provider: config.boardProvider?.provider ?? "github",
|
|
19248
|
-
projectNumber: boardInfo.number
|
|
19479
|
+
projectNumber: boardInfo.number,
|
|
19480
|
+
projectTitle: boardInfo.title
|
|
19249
19481
|
}
|
|
19250
19482
|
});
|
|
19251
19483
|
if (!result.success) {
|
|
@@ -19342,7 +19574,8 @@ function boardCommand(program2) {
|
|
|
19342
19574
|
const result = saveConfig(cwd, {
|
|
19343
19575
|
boardProvider: {
|
|
19344
19576
|
...config.boardProvider,
|
|
19345
|
-
projectNumber: boardInfo.number
|
|
19577
|
+
projectNumber: boardInfo.number,
|
|
19578
|
+
projectTitle: boardInfo.title
|
|
19346
19579
|
}
|
|
19347
19580
|
});
|
|
19348
19581
|
if (!result.success) {
|