chief-clancy 0.5.3 → 0.5.5
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 +3 -3
- package/dist/bundle/clancy-afk.js +2 -2
- package/dist/bundle/clancy-once.js +54 -28
- package/dist/schemas/bitbucket-pr.d.ts +122 -0
- package/dist/schemas/bitbucket-pr.d.ts.map +1 -0
- package/dist/schemas/bitbucket-pr.js +69 -0
- package/dist/schemas/bitbucket-pr.js.map +1 -0
- package/dist/schemas/env.d.ts +31 -0
- package/dist/schemas/env.d.ts.map +1 -1
- package/dist/schemas/env.js +10 -0
- package/dist/schemas/env.js.map +1 -1
- package/dist/schemas/github.d.ts +60 -0
- package/dist/schemas/github.d.ts.map +1 -1
- package/dist/schemas/github.js +32 -0
- package/dist/schemas/github.js.map +1 -1
- package/dist/schemas/gitlab-mr.d.ts +62 -0
- package/dist/schemas/gitlab-mr.d.ts.map +1 -0
- package/dist/schemas/gitlab-mr.js +31 -0
- package/dist/schemas/gitlab-mr.js.map +1 -0
- package/dist/scripts/afk/afk.d.ts.map +1 -1
- package/dist/scripts/afk/afk.js +1 -8
- package/dist/scripts/afk/afk.js.map +1 -1
- package/dist/scripts/board/github/github.d.ts.map +1 -1
- package/dist/scripts/board/github/github.js +1 -2
- package/dist/scripts/board/github/github.js.map +1 -1
- package/dist/scripts/board/linear/linear.d.ts.map +1 -1
- package/dist/scripts/board/linear/linear.js +35 -4
- package/dist/scripts/board/linear/linear.js.map +1 -1
- package/dist/scripts/once/once.d.ts.map +1 -1
- package/dist/scripts/once/once.js +381 -53
- package/dist/scripts/once/once.js.map +1 -1
- package/dist/scripts/shared/env-schema/env-schema.d.ts.map +1 -1
- package/dist/scripts/shared/env-schema/env-schema.js +3 -2
- package/dist/scripts/shared/env-schema/env-schema.js.map +1 -1
- package/dist/scripts/shared/format/format.d.ts +11 -0
- package/dist/scripts/shared/format/format.d.ts.map +1 -0
- package/dist/scripts/shared/format/format.js +18 -0
- package/dist/scripts/shared/format/format.js.map +1 -0
- package/dist/scripts/shared/git-ops/git-ops.d.ts +18 -0
- package/dist/scripts/shared/git-ops/git-ops.d.ts.map +1 -1
- package/dist/scripts/shared/git-ops/git-ops.js +40 -0
- package/dist/scripts/shared/git-ops/git-ops.js.map +1 -1
- package/dist/scripts/shared/http/http.d.ts +2 -0
- package/dist/scripts/shared/http/http.d.ts.map +1 -1
- package/dist/scripts/shared/http/http.js +2 -0
- package/dist/scripts/shared/http/http.js.map +1 -1
- package/dist/scripts/shared/progress/progress.d.ts +44 -2
- package/dist/scripts/shared/progress/progress.d.ts.map +1 -1
- package/dist/scripts/shared/progress/progress.js +97 -2
- package/dist/scripts/shared/progress/progress.js.map +1 -1
- package/dist/scripts/shared/prompt/prompt.d.ts +27 -0
- package/dist/scripts/shared/prompt/prompt.d.ts.map +1 -1
- package/dist/scripts/shared/prompt/prompt.js +32 -7
- package/dist/scripts/shared/prompt/prompt.js.map +1 -1
- package/dist/scripts/shared/pull-request/bitbucket/bitbucket.d.ts +70 -0
- package/dist/scripts/shared/pull-request/bitbucket/bitbucket.d.ts.map +1 -0
- package/dist/scripts/shared/pull-request/bitbucket/bitbucket.js +251 -0
- package/dist/scripts/shared/pull-request/bitbucket/bitbucket.js.map +1 -0
- package/dist/scripts/shared/pull-request/github/github.d.ts +48 -0
- package/dist/scripts/shared/pull-request/github/github.d.ts.map +1 -0
- package/dist/scripts/shared/pull-request/github/github.js +133 -0
- package/dist/scripts/shared/pull-request/github/github.js.map +1 -0
- package/dist/scripts/shared/pull-request/gitlab/gitlab.d.ts +46 -0
- package/dist/scripts/shared/pull-request/gitlab/gitlab.d.ts.map +1 -0
- package/dist/scripts/shared/pull-request/gitlab/gitlab.js +154 -0
- package/dist/scripts/shared/pull-request/gitlab/gitlab.js.map +1 -0
- package/dist/scripts/shared/pull-request/post-pr/post-pr.d.ts +31 -0
- package/dist/scripts/shared/pull-request/post-pr/post-pr.d.ts.map +1 -0
- package/dist/scripts/shared/pull-request/post-pr/post-pr.js +61 -0
- package/dist/scripts/shared/pull-request/post-pr/post-pr.js.map +1 -0
- package/dist/scripts/shared/pull-request/pr-body/pr-body.d.ts +19 -0
- package/dist/scripts/shared/pull-request/pr-body/pr-body.d.ts.map +1 -0
- package/dist/scripts/shared/pull-request/pr-body/pr-body.js +42 -0
- package/dist/scripts/shared/pull-request/pr-body/pr-body.js.map +1 -0
- package/dist/scripts/shared/pull-request/rework-comment/rework-comment.d.ts +23 -0
- package/dist/scripts/shared/pull-request/rework-comment/rework-comment.d.ts.map +1 -0
- package/dist/scripts/shared/pull-request/rework-comment/rework-comment.js +30 -0
- package/dist/scripts/shared/pull-request/rework-comment/rework-comment.js.map +1 -0
- package/dist/scripts/shared/remote/remote.d.ts +41 -0
- package/dist/scripts/shared/remote/remote.d.ts.map +1 -0
- package/dist/scripts/shared/remote/remote.js +227 -0
- package/dist/scripts/shared/remote/remote.js.map +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/remote.d.ts +53 -0
- package/dist/types/remote.d.ts.map +1 -0
- package/dist/types/remote.js +5 -0
- package/dist/types/remote.js.map +1 -0
- package/package.json +1 -1
- package/src/roles/setup/workflows/init.md +106 -0
- package/src/roles/setup/workflows/scaffold.md +45 -0
- package/src/roles/setup/workflows/settings.md +81 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"github.js","sourceRoot":"","sources":["../../../../src/scripts/board/github/github.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,UAAU,CAAC;AAE7B,OAAO,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,
|
|
1
|
+
{"version":3,"file":"github.js","sourceRoot":"","sources":["../../../../src/scripts/board/github/github.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"linear.d.ts","sourceRoot":"","sources":["../../../../src/scripts/board/linear/linear.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAK/C,KAAK,SAAS,GAAG;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,OAAO,CAAC,OAAO,CAAC,CA8BlB;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"linear.d.ts","sourceRoot":"","sources":["../../../../src/scripts/board/linear/linear.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAK/C,KAAK,SAAS,GAAG;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,OAAO,CAAC,OAAO,CAAC,CA8BlB;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAsC1C;AAED;;;;;;;;GAQG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CACrD,CAAC,MAAM,GAAG;IACR,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC,GACF,SAAS,CACZ,CA0DA;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAuB7B;AAED;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,OAAO,CAAC,CAoBlB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC,CAelB"}
|
|
@@ -64,10 +64,41 @@ export async function linearGraphql(apiKey, query, variables) {
|
|
|
64
64
|
* @returns An object with `ok` and optional `error` message.
|
|
65
65
|
*/
|
|
66
66
|
export async function pingLinear(apiKey) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
let response;
|
|
68
|
+
try {
|
|
69
|
+
response = await fetch(LINEAR_API_URL, {
|
|
70
|
+
method: 'POST',
|
|
71
|
+
headers: {
|
|
72
|
+
Authorization: apiKey,
|
|
73
|
+
'Content-Type': 'application/json',
|
|
74
|
+
},
|
|
75
|
+
body: JSON.stringify({ query: '{ viewer { id } }' }),
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return { ok: false, error: '✗ Could not reach Linear — check network' };
|
|
80
|
+
}
|
|
81
|
+
if (!response.ok) {
|
|
82
|
+
if (response.status === 401 || response.status === 403) {
|
|
83
|
+
return {
|
|
84
|
+
ok: false,
|
|
85
|
+
error: '✗ Linear auth failed — check LINEAR_API_KEY',
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
ok: false,
|
|
90
|
+
error: `✗ Linear API returned HTTP ${response.status}`,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
const json = await response.json();
|
|
95
|
+
const parsed = linearViewerResponseSchema.safeParse(json);
|
|
96
|
+
if (parsed.success && parsed.data.data?.viewer?.id)
|
|
97
|
+
return { ok: true };
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// Invalid JSON — treat as auth issue
|
|
101
|
+
}
|
|
71
102
|
return { ok: false, error: '✗ Linear auth failed — check LINEAR_API_KEY' };
|
|
72
103
|
}
|
|
73
104
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"linear.js","sourceRoot":"","sources":["../../../../src/scripts/board/linear/linear.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EACL,+BAA+B,EAC/B,0BAA0B,EAC1B,0BAA0B,EAC1B,kCAAkC,GACnC,MAAM,qBAAqB,CAAC;AAG7B,MAAM,eAAe,GAAG,kBAAkB,CAAC;AAC3C,MAAM,cAAc,GAAG,gCAAgC,CAAC;AAaxD;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,OAAO,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACtC,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAc,EACd,KAAa,EACb,SAAmC;IAEnC,IAAI,QAAkB,CAAC;IAEvB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,KAAK,CAAC,cAAc,EAAE;YACrC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,aAAa,EAAE,MAAM;gBACrB,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;SAC3C,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CACV,gCAAgC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CACnF,CAAC;QACF,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,OAAO,CAAC,IAAI,CAAC,8BAA8B,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAC9D,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,CAAC;QACH,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;QACnD,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,MAAc;IAEd,
|
|
1
|
+
{"version":3,"file":"linear.js","sourceRoot":"","sources":["../../../../src/scripts/board/linear/linear.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"once.d.ts","sourceRoot":"","sources":["../../../src/scripts/once/once.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"once.d.ts","sourceRoot":"","sources":["../../../src/scripts/once/once.ts"],"names":[],"mappings":"AAsuBA;;;;;;;;;GASG;AACH,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA2SvD"}
|
|
@@ -17,20 +17,22 @@ import { computeTargetBranch, computeTicketBranch, } from '../../scripts/shared/
|
|
|
17
17
|
import { invokeClaudeSession } from '../../scripts/shared/claude-cli/claude-cli.js';
|
|
18
18
|
import { detectBoard } from '../../scripts/shared/env-schema/env-schema.js';
|
|
19
19
|
import { checkFeasibility } from '../../scripts/shared/feasibility/feasibility.js';
|
|
20
|
-
import {
|
|
20
|
+
import { formatDuration } from '../../scripts/shared/format/format.js';
|
|
21
|
+
import { checkout, currentBranch, deleteBranch, ensureBranch, fetchRemoteBranch, pushBranch, squashMerge, } from '../../scripts/shared/git-ops/git-ops.js';
|
|
21
22
|
import { sendNotification } from '../../scripts/shared/notify/notify.js';
|
|
22
23
|
import { runPreflight } from '../../scripts/shared/preflight/preflight.js';
|
|
23
|
-
import { appendProgress } from '../../scripts/shared/progress/progress.js';
|
|
24
|
-
import { buildPrompt } from '../../scripts/shared/prompt/prompt.js';
|
|
24
|
+
import { appendProgress, countReworkCycles, findEntriesWithStatus, } from '../../scripts/shared/progress/progress.js';
|
|
25
|
+
import { buildPrompt, buildReworkPrompt, } from '../../scripts/shared/prompt/prompt.js';
|
|
26
|
+
import { checkPrReviewState as checkBitbucketPrReviewState, checkServerPrReviewState as checkBitbucketServerPrReviewState, createPullRequest as createBitbucketPr, createServerPullRequest as createBitbucketServerPr, fetchPrReviewComments as fetchBitbucketPrReviewComments, fetchServerPrReviewComments as fetchBitbucketServerPrReviewComments, } from '../../scripts/shared/pull-request/bitbucket/bitbucket.js';
|
|
27
|
+
import { checkPrReviewState as checkGitHubPrReviewState, createPullRequest as createGitHubPr, fetchPrReviewComments as fetchGitHubPrReviewComments, } from '../../scripts/shared/pull-request/github/github.js';
|
|
28
|
+
import { checkMrReviewState as checkGitLabMrReviewState, createMergeRequest as createGitLabMr, fetchMrReviewComments as fetchGitLabMrReviewComments, } from '../../scripts/shared/pull-request/gitlab/gitlab.js';
|
|
29
|
+
import { buildPrBody } from '../../scripts/shared/pull-request/pr-body/pr-body.js';
|
|
30
|
+
import { buildApiBaseUrl, detectRemote, } from '../../scripts/shared/remote/remote.js';
|
|
25
31
|
import { bold, dim, green, red, yellow } from '../../utils/ansi/ansi.js';
|
|
26
32
|
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return `${secs}s`;
|
|
31
|
-
const mins = Math.floor(secs / 60);
|
|
32
|
-
const remSecs = secs % 60;
|
|
33
|
-
return remSecs > 0 ? `${mins}m ${remSecs}s` : `${mins}m`;
|
|
33
|
+
/** Type-safe access to shared env vars across all board configs. */
|
|
34
|
+
function sharedEnv(config) {
|
|
35
|
+
return config.env;
|
|
34
36
|
}
|
|
35
37
|
// ─── Board-specific fetch ────────────────────────────────────────────────────
|
|
36
38
|
async function fetchTicket(config) {
|
|
@@ -82,10 +84,99 @@ async function fetchTicket(config) {
|
|
|
82
84
|
parentInfo: ticket.parentIdentifier ?? 'none',
|
|
83
85
|
blockers: 'None',
|
|
84
86
|
linearIssueId: ticket.issueId,
|
|
87
|
+
issueId: ticket.issueId,
|
|
85
88
|
};
|
|
86
89
|
}
|
|
87
90
|
}
|
|
88
91
|
}
|
|
92
|
+
// ─── PR-based rework detection ────────────────────────────────────────────────
|
|
93
|
+
/**
|
|
94
|
+
* Check open PRs for review feedback requesting changes.
|
|
95
|
+
*
|
|
96
|
+
* Scans progress.txt for tickets with status PR_CREATED, then checks
|
|
97
|
+
* the corresponding PR's review state on the detected remote platform.
|
|
98
|
+
* If a reviewer has requested changes, returns the ticket and feedback.
|
|
99
|
+
*
|
|
100
|
+
* This is best-effort — errors are swallowed so the orchestrator
|
|
101
|
+
* can fall through to fresh ticket fetch.
|
|
102
|
+
*/
|
|
103
|
+
async function fetchReworkFromPrReview(config) {
|
|
104
|
+
const prCreated = findEntriesWithStatus(process.cwd(), 'PR_CREATED');
|
|
105
|
+
const reworked = findEntriesWithStatus(process.cwd(), 'REWORK');
|
|
106
|
+
const candidates = [...prCreated, ...reworked];
|
|
107
|
+
if (candidates.length === 0)
|
|
108
|
+
return undefined;
|
|
109
|
+
const platformOverride = sharedEnv(config).CLANCY_GIT_PLATFORM;
|
|
110
|
+
const remote = detectRemote(platformOverride);
|
|
111
|
+
if (remote.host === 'none' ||
|
|
112
|
+
remote.host === 'unknown' ||
|
|
113
|
+
remote.host === 'azure') {
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
const creds = resolveGitToken(config, remote);
|
|
117
|
+
if (!creds)
|
|
118
|
+
return undefined;
|
|
119
|
+
const apiBase = buildApiBaseUrl(remote, sharedEnv(config).CLANCY_GIT_API_URL);
|
|
120
|
+
if (!apiBase)
|
|
121
|
+
return undefined;
|
|
122
|
+
// Limit to first 5 candidates to avoid rate limits
|
|
123
|
+
const toCheck = candidates.slice(0, 5);
|
|
124
|
+
for (const entry of toCheck) {
|
|
125
|
+
const branch = computeTicketBranch(config.provider, entry.key);
|
|
126
|
+
// Convert progress timestamp (YYYY-MM-DD HH:MM) to ISO 8601 for API filtering.
|
|
127
|
+
// Only comments created AFTER this timestamp should trigger rework,
|
|
128
|
+
// preventing stale inline comments from causing infinite rework loops.
|
|
129
|
+
// Parse local timestamp (YYYY-MM-DD HH:MM) and convert to ISO 8601.
|
|
130
|
+
// Falls back to undefined if timestamp is invalid (skips filtering).
|
|
131
|
+
let since;
|
|
132
|
+
if (entry.timestamp) {
|
|
133
|
+
const date = new Date(entry.timestamp.replace(' ', 'T'));
|
|
134
|
+
since = Number.isNaN(date.getTime()) ? undefined : date.toISOString();
|
|
135
|
+
}
|
|
136
|
+
let reviewState;
|
|
137
|
+
switch (remote.host) {
|
|
138
|
+
case 'github':
|
|
139
|
+
reviewState = await checkGitHubPrReviewState(creds.token, `${remote.owner}/${remote.repo}`, branch, remote.owner, apiBase, since);
|
|
140
|
+
break;
|
|
141
|
+
case 'gitlab':
|
|
142
|
+
reviewState = await checkGitLabMrReviewState(creds.token, apiBase, remote.projectPath, branch, since);
|
|
143
|
+
break;
|
|
144
|
+
case 'bitbucket':
|
|
145
|
+
reviewState = await checkBitbucketPrReviewState(creds.username, creds.token, remote.workspace, remote.repoSlug, branch, since);
|
|
146
|
+
break;
|
|
147
|
+
case 'bitbucket-server':
|
|
148
|
+
reviewState = await checkBitbucketServerPrReviewState(creds.token, apiBase, remote.projectKey, remote.repoSlug, branch, since);
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
if (reviewState?.changesRequested) {
|
|
152
|
+
// Fetch review comments for the PR
|
|
153
|
+
let feedback = [];
|
|
154
|
+
switch (remote.host) {
|
|
155
|
+
case 'github':
|
|
156
|
+
feedback = await fetchGitHubPrReviewComments(creds.token, `${remote.owner}/${remote.repo}`, reviewState.prNumber, apiBase, since);
|
|
157
|
+
break;
|
|
158
|
+
case 'gitlab':
|
|
159
|
+
feedback = await fetchGitLabMrReviewComments(creds.token, apiBase, remote.projectPath, reviewState.prNumber, since);
|
|
160
|
+
break;
|
|
161
|
+
case 'bitbucket':
|
|
162
|
+
feedback = await fetchBitbucketPrReviewComments(creds.username, creds.token, remote.workspace, remote.repoSlug, reviewState.prNumber, since);
|
|
163
|
+
break;
|
|
164
|
+
case 'bitbucket-server':
|
|
165
|
+
feedback = await fetchBitbucketServerPrReviewComments(creds.token, apiBase, remote.projectKey, remote.repoSlug, reviewState.prNumber, since);
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
const ticket = {
|
|
169
|
+
key: entry.key,
|
|
170
|
+
title: entry.summary,
|
|
171
|
+
description: '',
|
|
172
|
+
parentInfo: 'none',
|
|
173
|
+
blockers: 'None',
|
|
174
|
+
};
|
|
175
|
+
return { ticket, feedback, prNumber: reviewState.prNumber };
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return undefined;
|
|
179
|
+
}
|
|
89
180
|
// ─── Board-specific ping ─────────────────────────────────────────────────────
|
|
90
181
|
async function pingBoard(config) {
|
|
91
182
|
switch (config.provider) {
|
|
@@ -158,6 +249,192 @@ async function transitionToStatus(config, ticket, statusName) {
|
|
|
158
249
|
}
|
|
159
250
|
}
|
|
160
251
|
}
|
|
252
|
+
// ─── PR/MR creation ──────────────────────────────────────────────────────────
|
|
253
|
+
/**
|
|
254
|
+
* Resolve a git host token from the board config's env.
|
|
255
|
+
*
|
|
256
|
+
* For GitHub boards, `GITHUB_TOKEN` is always present.
|
|
257
|
+
* For Jira/Linear boards, check the shared optional vars.
|
|
258
|
+
*/
|
|
259
|
+
function resolveGitToken(config, remote) {
|
|
260
|
+
const env = sharedEnv(config);
|
|
261
|
+
switch (remote.host) {
|
|
262
|
+
case 'github':
|
|
263
|
+
if (env.GITHUB_TOKEN)
|
|
264
|
+
return { token: env.GITHUB_TOKEN };
|
|
265
|
+
break;
|
|
266
|
+
case 'gitlab':
|
|
267
|
+
if (env.GITLAB_TOKEN)
|
|
268
|
+
return { token: env.GITLAB_TOKEN };
|
|
269
|
+
break;
|
|
270
|
+
case 'bitbucket':
|
|
271
|
+
if (env.BITBUCKET_USER && env.BITBUCKET_TOKEN)
|
|
272
|
+
return { token: env.BITBUCKET_TOKEN, username: env.BITBUCKET_USER };
|
|
273
|
+
break;
|
|
274
|
+
case 'bitbucket-server':
|
|
275
|
+
if (env.BITBUCKET_TOKEN)
|
|
276
|
+
return { token: env.BITBUCKET_TOKEN };
|
|
277
|
+
break;
|
|
278
|
+
}
|
|
279
|
+
return undefined;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Attempt to create a PR/MR on the detected remote platform.
|
|
283
|
+
*/
|
|
284
|
+
async function attemptPrCreation(config, remote, ticketBranch, targetBranch, title, body) {
|
|
285
|
+
const creds = resolveGitToken(config, remote);
|
|
286
|
+
if (!creds)
|
|
287
|
+
return undefined;
|
|
288
|
+
const apiBase = buildApiBaseUrl(remote, sharedEnv(config).CLANCY_GIT_API_URL);
|
|
289
|
+
if (!apiBase)
|
|
290
|
+
return undefined;
|
|
291
|
+
switch (remote.host) {
|
|
292
|
+
case 'github':
|
|
293
|
+
return createGitHubPr(creds.token, `${remote.owner}/${remote.repo}`, ticketBranch, targetBranch, title, body, apiBase);
|
|
294
|
+
case 'gitlab':
|
|
295
|
+
return createGitLabMr(creds.token, apiBase, remote.projectPath, ticketBranch, targetBranch, title, body);
|
|
296
|
+
case 'bitbucket':
|
|
297
|
+
return createBitbucketPr(creds.username, creds.token, remote.workspace, remote.repoSlug, ticketBranch, targetBranch, title, body);
|
|
298
|
+
case 'bitbucket-server':
|
|
299
|
+
return createBitbucketServerPr(creds.token, apiBase, remote.projectKey, remote.repoSlug, ticketBranch, targetBranch, title, body);
|
|
300
|
+
default:
|
|
301
|
+
return undefined;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Build a manual PR/MR URL for the user to click.
|
|
306
|
+
*/
|
|
307
|
+
function buildManualPrUrl(remote, ticketBranch, targetBranch) {
|
|
308
|
+
const encodedTicket = encodeURIComponent(ticketBranch);
|
|
309
|
+
const encodedTarget = encodeURIComponent(targetBranch);
|
|
310
|
+
if (remote.host === 'github') {
|
|
311
|
+
return `https://${remote.hostname}/${remote.owner}/${remote.repo}/compare/${encodedTarget}...${encodedTicket}`;
|
|
312
|
+
}
|
|
313
|
+
if (remote.host === 'gitlab') {
|
|
314
|
+
return `https://${remote.hostname}/${remote.projectPath}/-/merge_requests/new?merge_request[source_branch]=${encodedTicket}&merge_request[target_branch]=${encodedTarget}`;
|
|
315
|
+
}
|
|
316
|
+
if (remote.host === 'bitbucket') {
|
|
317
|
+
return `https://${remote.hostname}/${remote.workspace}/${remote.repoSlug}/pull-requests/new?source=${encodedTicket}&dest=${encodedTarget}`;
|
|
318
|
+
}
|
|
319
|
+
return undefined;
|
|
320
|
+
}
|
|
321
|
+
// ─── Delivery paths ──────────────────────────────────────────────────────────
|
|
322
|
+
/**
|
|
323
|
+
* Epic/parent flow: squash merge locally, delete branch, transition to Done.
|
|
324
|
+
*/
|
|
325
|
+
async function deliverViaEpicMerge(config, ticket, ticketBranch, targetBranch) {
|
|
326
|
+
checkout(targetBranch);
|
|
327
|
+
const commitMsg = `feat(${ticket.key}): ${ticket.title}`;
|
|
328
|
+
const hadChanges = squashMerge(ticketBranch, commitMsg);
|
|
329
|
+
if (!hadChanges) {
|
|
330
|
+
console.log(yellow('⚠ No changes staged after squash merge. Claude may not have committed any work.'));
|
|
331
|
+
}
|
|
332
|
+
deleteBranch(ticketBranch);
|
|
333
|
+
// Transition to Done / close issue (best-effort)
|
|
334
|
+
const statusDone = config.env.CLANCY_STATUS_DONE;
|
|
335
|
+
if (config.provider === 'github') {
|
|
336
|
+
const issueNumber = parseInt(ticket.key.replace('#', ''), 10);
|
|
337
|
+
if (Number.isNaN(issueNumber)) {
|
|
338
|
+
console.log(`⚠ Could not parse issue number from ${ticket.key}. Close it manually on GitHub.`);
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
const closed = await closeIssue(config.env.GITHUB_TOKEN, config.env.GITHUB_REPO, issueNumber);
|
|
342
|
+
if (!closed) {
|
|
343
|
+
console.log(`⚠ Could not close issue ${ticket.key}. Close it manually on GitHub.`);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
else if (statusDone) {
|
|
348
|
+
await transitionToStatus(config, ticket, statusDone);
|
|
349
|
+
}
|
|
350
|
+
appendProgress(process.cwd(), ticket.key, ticket.title, 'DONE');
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* PR flow: push branch to remote, create PR/MR, transition to In Review.
|
|
354
|
+
*
|
|
355
|
+
* @returns `false` if the push failed (caller should handle early return).
|
|
356
|
+
*/
|
|
357
|
+
async function deliverViaPullRequest(config, ticket, ticketBranch, targetBranch, startTime) {
|
|
358
|
+
const pushed = pushBranch(ticketBranch);
|
|
359
|
+
if (!pushed) {
|
|
360
|
+
console.log(yellow(`⚠ Could not push ${ticketBranch} to origin.`));
|
|
361
|
+
console.log(dim(' The branch is still available locally. Push manually:'));
|
|
362
|
+
console.log(dim(` git push -u origin ${ticketBranch}`));
|
|
363
|
+
appendProgress(process.cwd(), ticket.key, ticket.title, 'PUSH_FAILED');
|
|
364
|
+
checkout(targetBranch);
|
|
365
|
+
const elapsed = formatDuration(Date.now() - startTime);
|
|
366
|
+
console.log('');
|
|
367
|
+
console.log(yellow(`⚠ ${ticket.key} implemented but push failed`) +
|
|
368
|
+
dim(` (${elapsed})`));
|
|
369
|
+
return false;
|
|
370
|
+
}
|
|
371
|
+
console.log(green(` ✓ Pushed ${ticketBranch}`));
|
|
372
|
+
// Attempt PR/MR creation
|
|
373
|
+
const platformOverride = sharedEnv(config).CLANCY_GIT_PLATFORM;
|
|
374
|
+
const remote = detectRemote(platformOverride);
|
|
375
|
+
const prTitle = `feat(${ticket.key}): ${ticket.title}`;
|
|
376
|
+
const prBody = buildPrBody(config, {
|
|
377
|
+
key: ticket.key,
|
|
378
|
+
title: ticket.title,
|
|
379
|
+
description: ticket.description,
|
|
380
|
+
provider: config.provider,
|
|
381
|
+
});
|
|
382
|
+
if (remote.host !== 'none' &&
|
|
383
|
+
remote.host !== 'unknown' &&
|
|
384
|
+
remote.host !== 'azure') {
|
|
385
|
+
const pr = await attemptPrCreation(config, remote, ticketBranch, targetBranch, prTitle, prBody);
|
|
386
|
+
if (pr?.ok) {
|
|
387
|
+
console.log(green(` ✓ PR created: ${pr.url}`));
|
|
388
|
+
appendProgress(process.cwd(), ticket.key, ticket.title, 'PR_CREATED');
|
|
389
|
+
}
|
|
390
|
+
else if (pr && !pr.ok && pr.alreadyExists) {
|
|
391
|
+
console.log(yellow(` ⚠ A PR/MR already exists for ${ticketBranch}. Branch pushed.`));
|
|
392
|
+
appendProgress(process.cwd(), ticket.key, ticket.title, 'PUSHED');
|
|
393
|
+
}
|
|
394
|
+
else if (pr && !pr.ok) {
|
|
395
|
+
console.log(yellow(` ⚠ PR/MR creation failed: ${pr.error}`));
|
|
396
|
+
const manualUrl = buildManualPrUrl(remote, ticketBranch, targetBranch);
|
|
397
|
+
if (manualUrl) {
|
|
398
|
+
console.log(dim(` Create one manually: ${manualUrl}`));
|
|
399
|
+
}
|
|
400
|
+
else {
|
|
401
|
+
console.log(dim(' Branch pushed — create a PR/MR manually.'));
|
|
402
|
+
}
|
|
403
|
+
appendProgress(process.cwd(), ticket.key, ticket.title, 'PUSHED');
|
|
404
|
+
}
|
|
405
|
+
else {
|
|
406
|
+
// No token available for this platform
|
|
407
|
+
const manualUrl = buildManualPrUrl(remote, ticketBranch, targetBranch);
|
|
408
|
+
if (manualUrl) {
|
|
409
|
+
console.log(dim(` Create a PR: ${manualUrl}`));
|
|
410
|
+
}
|
|
411
|
+
else {
|
|
412
|
+
console.log(dim(' Branch pushed to remote. Create a PR/MR manually.'));
|
|
413
|
+
}
|
|
414
|
+
appendProgress(process.cwd(), ticket.key, ticket.title, 'PUSHED');
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
else if (remote.host === 'none') {
|
|
418
|
+
console.log(yellow(`⚠ No git remote configured. Branch available locally: ${ticketBranch}`));
|
|
419
|
+
appendProgress(process.cwd(), ticket.key, ticket.title, 'LOCAL');
|
|
420
|
+
}
|
|
421
|
+
else {
|
|
422
|
+
// Unknown or Azure remote — just note the push
|
|
423
|
+
console.log(dim(' Branch pushed to remote. Create a PR/MR manually.'));
|
|
424
|
+
appendProgress(process.cwd(), ticket.key, ticket.title, 'PUSHED');
|
|
425
|
+
}
|
|
426
|
+
// Transition to In Review (not Done — PR hasn't been merged yet)
|
|
427
|
+
// For GitHub Issues: do NOT close — PR body has "Closes #N" for auto-close on merge
|
|
428
|
+
if (config.provider !== 'github') {
|
|
429
|
+
const statusReview = config.env.CLANCY_STATUS_REVIEW ?? config.env.CLANCY_STATUS_DONE;
|
|
430
|
+
if (statusReview) {
|
|
431
|
+
await transitionToStatus(config, ticket, statusReview);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
// Switch back to target branch
|
|
435
|
+
checkout(targetBranch);
|
|
436
|
+
return true;
|
|
437
|
+
}
|
|
161
438
|
// ─── Main orchestrator ───────────────────────────────────────────────────────
|
|
162
439
|
/**
|
|
163
440
|
* Run the once orchestrator — full ticket lifecycle.
|
|
@@ -209,12 +486,42 @@ export async function run(argv) {
|
|
|
209
486
|
return;
|
|
210
487
|
}
|
|
211
488
|
console.log(green('✅ Preflight passed'));
|
|
212
|
-
// 5.
|
|
213
|
-
|
|
489
|
+
// 5. Check rework — PR-based detection, then fresh ticket
|
|
490
|
+
let isRework = false;
|
|
491
|
+
let prFeedback;
|
|
492
|
+
let ticket;
|
|
493
|
+
// PR-based rework (automatic, no config needed)
|
|
494
|
+
try {
|
|
495
|
+
const prRework = await fetchReworkFromPrReview(config);
|
|
496
|
+
if (prRework) {
|
|
497
|
+
isRework = true;
|
|
498
|
+
ticket = prRework.ticket;
|
|
499
|
+
prFeedback = prRework.feedback;
|
|
500
|
+
console.log(yellow(` ↻ PR rework: [${ticket.key}] ${ticket.title}`));
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
catch {
|
|
504
|
+
// Best-effort — fall through to fresh ticket
|
|
505
|
+
}
|
|
506
|
+
if (!ticket) {
|
|
507
|
+
// Fresh ticket
|
|
508
|
+
ticket = await fetchTicket(config);
|
|
509
|
+
}
|
|
214
510
|
if (!ticket) {
|
|
215
511
|
console.log(dim('No tickets found. All done!'));
|
|
216
512
|
return;
|
|
217
513
|
}
|
|
514
|
+
// 5a. Max rework guard
|
|
515
|
+
if (isRework) {
|
|
516
|
+
const parsed = parseInt(sharedEnv(config).CLANCY_MAX_REWORK ?? '3', 10);
|
|
517
|
+
const maxRework = Number.isFinite(parsed) && parsed > 0 ? parsed : 3;
|
|
518
|
+
const cycles = countReworkCycles(process.cwd(), ticket.key);
|
|
519
|
+
if (cycles >= maxRework) {
|
|
520
|
+
console.log(yellow(`⚠ ${ticket.key} has reached max rework cycles (${maxRework}) — needs human intervention`));
|
|
521
|
+
appendProgress(process.cwd(), ticket.key, ticket.title, 'SKIPPED');
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
218
525
|
// 6. Compute branches
|
|
219
526
|
const baseBranch = config.env.CLANCY_BASE_BRANCH ?? 'main';
|
|
220
527
|
const parent = ticket.parentInfo !== 'none' ? ticket.parentInfo : undefined;
|
|
@@ -226,6 +533,9 @@ export async function run(argv) {
|
|
|
226
533
|
console.log('');
|
|
227
534
|
console.log(yellow('── Dry Run ──────────────────────────────────────'));
|
|
228
535
|
console.log(` Ticket: ${bold(`[${ticket.key}]`)} ${ticket.title}`);
|
|
536
|
+
if (isRework) {
|
|
537
|
+
console.log(` Mode: Rework`);
|
|
538
|
+
}
|
|
229
539
|
console.log(` ${parentLabel}:${' '.repeat(14 - parentLabel.length)}${ticket.parentInfo}`);
|
|
230
540
|
if (config.provider !== 'github') {
|
|
231
541
|
console.log(` Blockers: ${ticket.blockers}`);
|
|
@@ -247,9 +557,8 @@ export async function run(argv) {
|
|
|
247
557
|
console.log(yellow(` Blockers: ${ticket.blockers}`));
|
|
248
558
|
}
|
|
249
559
|
console.log('');
|
|
250
|
-
// 9. Feasibility check (skipped
|
|
251
|
-
|
|
252
|
-
if (!skipFeasibility) {
|
|
560
|
+
// 9. Feasibility check (skipped for rework tickets and --skip-feasibility)
|
|
561
|
+
if (!isRework && !skipFeasibility) {
|
|
253
562
|
console.log(dim(' Checking feasibility...'));
|
|
254
563
|
const feasibility = checkFeasibility({
|
|
255
564
|
key: ticket.key,
|
|
@@ -267,61 +576,80 @@ export async function run(argv) {
|
|
|
267
576
|
console.log('');
|
|
268
577
|
// 10. Git: set up branches
|
|
269
578
|
originalBranch = currentBranch();
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
579
|
+
if (isRework) {
|
|
580
|
+
// PR-flow rework: try to fetch the existing feature branch from remote
|
|
581
|
+
ensureBranch(targetBranch, baseBranch);
|
|
582
|
+
const fetched = fetchRemoteBranch(ticketBranch);
|
|
583
|
+
if (fetched) {
|
|
584
|
+
checkout(ticketBranch);
|
|
585
|
+
}
|
|
586
|
+
else {
|
|
587
|
+
// Branch missing from remote — create fresh branch from target
|
|
588
|
+
checkout(targetBranch);
|
|
589
|
+
checkout(ticketBranch, true);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
else {
|
|
593
|
+
// Normal flow
|
|
594
|
+
ensureBranch(targetBranch, baseBranch);
|
|
595
|
+
checkout(targetBranch);
|
|
596
|
+
checkout(ticketBranch, true);
|
|
597
|
+
}
|
|
273
598
|
// 11. Transition to In Progress (best-effort)
|
|
274
599
|
const statusInProgress = config.env.CLANCY_STATUS_IN_PROGRESS;
|
|
275
600
|
if (statusInProgress) {
|
|
276
601
|
await transitionToStatus(config, ticket, statusInProgress);
|
|
277
602
|
}
|
|
278
603
|
// 12. Build prompt and invoke Claude
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
604
|
+
let prompt;
|
|
605
|
+
if (isRework) {
|
|
606
|
+
prompt = buildReworkPrompt({
|
|
607
|
+
key: ticket.key,
|
|
608
|
+
title: ticket.title,
|
|
609
|
+
description: ticket.description,
|
|
610
|
+
provider: config.provider,
|
|
611
|
+
feedbackComments: prFeedback ?? [],
|
|
612
|
+
previousContext: undefined, // V1: no diff context yet
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
else {
|
|
616
|
+
prompt = buildPrompt({
|
|
617
|
+
provider: config.provider,
|
|
618
|
+
key: ticket.key,
|
|
619
|
+
title: ticket.title,
|
|
620
|
+
description: ticket.description,
|
|
621
|
+
parentInfo: ticket.parentInfo,
|
|
622
|
+
blockers: config.provider !== 'github' ? ticket.blockers : undefined,
|
|
623
|
+
});
|
|
624
|
+
}
|
|
287
625
|
const claudeOk = invokeClaudeSession(prompt, config.env.CLANCY_MODEL);
|
|
288
626
|
if (!claudeOk) {
|
|
289
627
|
console.log(yellow('⚠ Claude session exited with an error. Skipping merge.'));
|
|
290
628
|
return;
|
|
291
629
|
}
|
|
292
|
-
// 13.
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
const issueNumber = parseInt(ticket.key.replace('#', ''), 10);
|
|
305
|
-
if (Number.isNaN(issueNumber)) {
|
|
306
|
-
console.log(`⚠ Could not parse issue number from ${ticket.key}. Close it manually on GitHub.`);
|
|
307
|
-
}
|
|
308
|
-
else {
|
|
309
|
-
const closed = await closeIssue(config.env.GITHUB_TOKEN, config.env.GITHUB_REPO, issueNumber);
|
|
310
|
-
if (!closed) {
|
|
311
|
-
console.log(`⚠ Could not close issue ${ticket.key}. Close it manually on GitHub.`);
|
|
312
|
-
}
|
|
313
|
-
}
|
|
630
|
+
// 13. Deliver — epic merge or PR flow
|
|
631
|
+
const hasParent = ticket.parentInfo !== 'none';
|
|
632
|
+
if (isRework) {
|
|
633
|
+
// PR-flow rework: push to existing branch, PR updates automatically
|
|
634
|
+
const delivered = await deliverViaPullRequest(config, ticket, ticketBranch, targetBranch, startTime);
|
|
635
|
+
if (!delivered)
|
|
636
|
+
return;
|
|
637
|
+
// Override progress to REWORK (deliverViaPullRequest logs PR_CREATED/PUSHED)
|
|
638
|
+
appendProgress(process.cwd(), ticket.key, ticket.title, 'REWORK');
|
|
639
|
+
}
|
|
640
|
+
else if (hasParent) {
|
|
641
|
+
await deliverViaEpicMerge(config, ticket, ticketBranch, targetBranch);
|
|
314
642
|
}
|
|
315
|
-
else
|
|
316
|
-
await
|
|
643
|
+
else {
|
|
644
|
+
const delivered = await deliverViaPullRequest(config, ticket, ticketBranch, targetBranch, startTime);
|
|
645
|
+
if (!delivered)
|
|
646
|
+
return;
|
|
317
647
|
}
|
|
318
|
-
// 16. Log progress
|
|
319
|
-
appendProgress(process.cwd(), ticket.key, ticket.title, 'DONE');
|
|
320
648
|
const elapsed = formatDuration(Date.now() - startTime);
|
|
321
649
|
console.log('');
|
|
322
650
|
console.log(green(`🏁 ${ticket.key} complete`) + dim(` (${elapsed})`));
|
|
323
651
|
console.log(dim(' "Bake \'em away, toys."'));
|
|
324
|
-
//
|
|
652
|
+
// 14. Send notification (best-effort)
|
|
325
653
|
const webhook = config.env.CLANCY_NOTIFY_WEBHOOK;
|
|
326
654
|
if (webhook) {
|
|
327
655
|
await sendNotification(webhook, `✓ Clancy completed [${ticket.key}] ${ticket.title}`);
|