chief-clancy 0.5.12 → 0.7.0
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 +15 -8
- package/dist/bundle/clancy-afk.js +6 -2
- package/dist/bundle/clancy-once.js +71 -48
- package/dist/installer/hook-installer/hook-installer.d.ts +2 -0
- package/dist/installer/hook-installer/hook-installer.d.ts.map +1 -1
- package/dist/installer/hook-installer/hook-installer.js +36 -1
- package/dist/installer/hook-installer/hook-installer.js.map +1 -1
- package/dist/installer/install.js +16 -1
- package/dist/installer/install.js.map +1 -1
- package/dist/schemas/env.d.ts +36 -0
- package/dist/schemas/env.d.ts.map +1 -1
- package/dist/schemas/env.js +11 -0
- package/dist/schemas/env.js.map +1 -1
- package/dist/schemas/github-issues.d.ts +6 -0
- package/dist/schemas/github-issues.d.ts.map +1 -1
- package/dist/schemas/github-issues.js +3 -0
- package/dist/schemas/github-issues.js.map +1 -1
- package/dist/schemas/jira.d.ts +21 -0
- package/dist/schemas/jira.d.ts.map +1 -1
- package/dist/schemas/jira.js +18 -0
- package/dist/schemas/jira.js.map +1 -1
- package/dist/schemas/linear.d.ts +41 -0
- package/dist/schemas/linear.d.ts.map +1 -1
- package/dist/schemas/linear.js +34 -0
- package/dist/schemas/linear.js.map +1 -1
- package/dist/scripts/afk/afk.d.ts.map +1 -1
- package/dist/scripts/afk/afk.js +28 -0
- package/dist/scripts/afk/afk.js.map +1 -1
- package/dist/scripts/afk/report/report.d.ts +47 -0
- package/dist/scripts/afk/report/report.d.ts.map +1 -0
- package/dist/scripts/afk/report/report.js +194 -0
- package/dist/scripts/afk/report/report.js.map +1 -0
- package/dist/scripts/board/github/github.d.ts +33 -3
- package/dist/scripts/board/github/github.d.ts.map +1 -1
- package/dist/scripts/board/github/github.js +112 -27
- package/dist/scripts/board/github/github.js.map +1 -1
- package/dist/scripts/board/jira/jira.d.ts +36 -4
- package/dist/scripts/board/jira/jira.d.ts.map +1 -1
- package/dist/scripts/board/jira/jira.js +138 -65
- package/dist/scripts/board/jira/jira.js.map +1 -1
- package/dist/scripts/board/linear/linear.d.ts +32 -5
- package/dist/scripts/board/linear/linear.d.ts.map +1 -1
- package/dist/scripts/board/linear/linear.js +135 -17
- package/dist/scripts/board/linear/linear.js.map +1 -1
- package/dist/scripts/once/board-ops/board-ops.d.ts.map +1 -1
- package/dist/scripts/once/board-ops/board-ops.js +1 -1
- package/dist/scripts/once/board-ops/board-ops.js.map +1 -1
- package/dist/scripts/once/cost/cost.d.ts +10 -0
- package/dist/scripts/once/cost/cost.d.ts.map +1 -0
- package/dist/scripts/once/cost/cost.js +23 -0
- package/dist/scripts/once/cost/cost.js.map +1 -0
- package/dist/scripts/once/deliver/deliver.d.ts.map +1 -1
- package/dist/scripts/once/deliver/deliver.js +18 -1
- package/dist/scripts/once/deliver/deliver.js.map +1 -1
- package/dist/scripts/once/fetch-ticket/fetch-ticket.d.ts +19 -1
- package/dist/scripts/once/fetch-ticket/fetch-ticket.d.ts.map +1 -1
- package/dist/scripts/once/fetch-ticket/fetch-ticket.js +93 -29
- package/dist/scripts/once/fetch-ticket/fetch-ticket.js.map +1 -1
- package/dist/scripts/once/lock/lock.d.ts +17 -0
- package/dist/scripts/once/lock/lock.d.ts.map +1 -0
- package/dist/scripts/once/lock/lock.js +70 -0
- package/dist/scripts/once/lock/lock.js.map +1 -0
- package/dist/scripts/once/once.d.ts.map +1 -1
- package/dist/scripts/once/once.js +100 -4
- package/dist/scripts/once/once.js.map +1 -1
- package/dist/scripts/once/resume/resume.d.ts +24 -0
- package/dist/scripts/once/resume/resume.d.ts.map +1 -0
- package/dist/scripts/once/resume/resume.js +159 -0
- package/dist/scripts/once/resume/resume.js.map +1 -0
- package/dist/scripts/shared/format/format.d.ts.map +1 -1
- package/dist/scripts/shared/format/format.js +6 -1
- package/dist/scripts/shared/format/format.js.map +1 -1
- package/dist/scripts/shared/progress/progress.d.ts +18 -2
- package/dist/scripts/shared/progress/progress.d.ts.map +1 -1
- package/dist/scripts/shared/progress/progress.js +31 -4
- package/dist/scripts/shared/progress/progress.js.map +1 -1
- package/dist/scripts/shared/pull-request/pr-body/pr-body.d.ts +2 -1
- package/dist/scripts/shared/pull-request/pr-body/pr-body.d.ts.map +1 -1
- package/dist/scripts/shared/pull-request/pr-body/pr-body.js +10 -1
- package/dist/scripts/shared/pull-request/pr-body/pr-body.js.map +1 -1
- package/dist/types/remote.d.ts +1 -1
- package/dist/types/remote.d.ts.map +1 -1
- package/hooks/clancy-branch-guard.js +129 -0
- package/hooks/clancy-check-update.js +43 -0
- package/hooks/clancy-context-monitor.js +134 -46
- package/hooks/clancy-post-compact.js +53 -0
- package/hooks/package.json +3 -0
- package/package.json +3 -2
- package/src/agents/devils-advocate.md +53 -0
- package/src/agents/verification-gate.md +128 -0
- package/src/roles/planner/workflows/approve-plan.md +2 -2
- package/src/roles/reviewer/workflows/logs.md +9 -6
- package/src/roles/setup/commands/help.md +7 -0
- package/src/roles/setup/workflows/init.md +111 -6
- package/src/roles/setup/workflows/scaffold.md +57 -0
- package/src/roles/setup/workflows/settings.md +145 -0
- package/src/roles/setup/workflows/update.md +18 -0
- package/src/roles/strategist/commands/approve-brief.md +20 -0
- package/src/roles/strategist/commands/brief.md +27 -0
- package/src/roles/strategist/workflows/approve-brief.md +763 -0
- package/src/roles/strategist/workflows/brief.md +732 -0
- package/src/templates/CLAUDE.md +8 -1
package/dist/scripts/afk/afk.js
CHANGED
|
@@ -11,7 +11,9 @@ import { dirname, join, resolve } from 'node:path';
|
|
|
11
11
|
import { setTimeout as sleep } from 'node:timers/promises';
|
|
12
12
|
import { fileURLToPath } from 'node:url';
|
|
13
13
|
import { formatDuration } from '../../scripts/shared/format/format.js';
|
|
14
|
+
import { sendNotification } from '../../scripts/shared/notify/notify.js';
|
|
14
15
|
import { bold, dim, green, red } from '../../utils/ansi/ansi.js';
|
|
16
|
+
import { generateSessionReport } from './report/report.js';
|
|
15
17
|
/** Stop condition patterns matched against script output. */
|
|
16
18
|
const STOP_PATTERNS = {
|
|
17
19
|
noTickets: /No tickets found|No issues found|All done/,
|
|
@@ -75,6 +77,7 @@ export async function runAfkLoop(scriptDir, maxIterations = 5) {
|
|
|
75
77
|
encoding: 'utf8',
|
|
76
78
|
stdio: ['inherit', 'pipe', 'inherit'],
|
|
77
79
|
cwd: process.cwd(),
|
|
80
|
+
env: { ...process.env, CLANCY_AFK_MODE: '1' },
|
|
78
81
|
});
|
|
79
82
|
const output = result.stdout ?? '';
|
|
80
83
|
if (output) {
|
|
@@ -92,6 +95,7 @@ export async function runAfkLoop(scriptDir, maxIterations = 5) {
|
|
|
92
95
|
console.log(dim(` Iteration ${i} took ${iterElapsed}`));
|
|
93
96
|
console.log(`\n${condition.reason}`);
|
|
94
97
|
console.log(dim(` Total: ${i} iteration${i > 1 ? 's' : ''} in ${totalElapsed}`));
|
|
98
|
+
generateAndSendReport(loopStart);
|
|
95
99
|
return;
|
|
96
100
|
}
|
|
97
101
|
console.log(dim(` Iteration ${i} took ${iterElapsed}`));
|
|
@@ -106,6 +110,30 @@ export async function runAfkLoop(scriptDir, maxIterations = 5) {
|
|
|
106
110
|
dim(` (${totalElapsed})`));
|
|
107
111
|
console.log(dim(' "That\'s some good police work."'));
|
|
108
112
|
console.log(dim(' Run clancy-afk again to continue.'));
|
|
113
|
+
generateAndSendReport(loopStart);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Generate a session report and optionally send a webhook notification.
|
|
117
|
+
*/
|
|
118
|
+
function generateAndSendReport(loopStart) {
|
|
119
|
+
try {
|
|
120
|
+
const report = generateSessionReport(process.cwd(), loopStart, Date.now());
|
|
121
|
+
console.log('');
|
|
122
|
+
console.log(dim('─── Session Report ───'));
|
|
123
|
+
console.log(report);
|
|
124
|
+
const webhook = process.env.CLANCY_NOTIFY_WEBHOOK;
|
|
125
|
+
if (webhook) {
|
|
126
|
+
const lines = report.split('\n');
|
|
127
|
+
const summaryLines = lines.filter((l) => l.startsWith('- Tickets') || l.startsWith('- Total'));
|
|
128
|
+
const summary = `Clancy AFK: ${summaryLines.join('. ')}. Report: .clancy/session-report.md`;
|
|
129
|
+
sendNotification(webhook, summary).catch(() => {
|
|
130
|
+
// Best-effort — webhook failure shouldn't crash
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
// Best-effort — report generation failure shouldn't crash the loop
|
|
136
|
+
}
|
|
109
137
|
}
|
|
110
138
|
// Main guard — self-execute when run directly (e.g. node .clancy/clancy-afk.js)
|
|
111
139
|
if (process.argv[1] &&
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"afk.js","sourceRoot":"","sources":["../../../src/scripts/afk/afk.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"afk.js","sourceRoot":"","sources":["../../../src/scripts/afk/afk.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** A parsed cost entry from costs.log. */
|
|
2
|
+
export type CostEntry = {
|
|
3
|
+
timestamp: string;
|
|
4
|
+
key: string;
|
|
5
|
+
duration: string;
|
|
6
|
+
tokens: string;
|
|
7
|
+
};
|
|
8
|
+
/** A ticket in the session report. */
|
|
9
|
+
export type SessionTicket = {
|
|
10
|
+
key: string;
|
|
11
|
+
summary: string;
|
|
12
|
+
status: string;
|
|
13
|
+
prNumber?: number;
|
|
14
|
+
duration?: string;
|
|
15
|
+
tokens?: string;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Parse costs.log and return entries with ISO timestamp >= the given threshold.
|
|
19
|
+
*
|
|
20
|
+
* Each line is expected to follow the format:
|
|
21
|
+
* `ISO-timestamp | KEY | Nmin | ~N tokens (estimated)`
|
|
22
|
+
*
|
|
23
|
+
* Lines that don't match are silently skipped.
|
|
24
|
+
*
|
|
25
|
+
* @param projectRoot - The project root directory.
|
|
26
|
+
* @param sinceMs - Only include entries with timestamp >= this value (ms since epoch).
|
|
27
|
+
* @returns Parsed cost entries from this session.
|
|
28
|
+
*/
|
|
29
|
+
export declare function parseCostsLog(projectRoot: string, sinceMs: number): CostEntry[];
|
|
30
|
+
/**
|
|
31
|
+
* Convert a progress timestamp (`YYYY-MM-DD HH:MM`) to milliseconds since epoch.
|
|
32
|
+
*
|
|
33
|
+
* @param timestamp - The progress file timestamp string.
|
|
34
|
+
* @returns Milliseconds since epoch, or `NaN` if the timestamp is invalid.
|
|
35
|
+
*/
|
|
36
|
+
export declare function progressTimestampToMs(timestamp: string): number;
|
|
37
|
+
/**
|
|
38
|
+
* Generate a session report from progress.txt and costs.log entries
|
|
39
|
+
* created during this AFK session.
|
|
40
|
+
*
|
|
41
|
+
* @param projectRoot - The project root directory.
|
|
42
|
+
* @param loopStartTime - When the AFK loop started (Date.now()).
|
|
43
|
+
* @param loopEndTime - When the AFK loop ended.
|
|
44
|
+
* @returns The report markdown string.
|
|
45
|
+
*/
|
|
46
|
+
export declare function generateSessionReport(projectRoot: string, loopStartTime: number, loopEndTime: number): string;
|
|
47
|
+
//# sourceMappingURL=report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../../../src/scripts/afk/report/report.ts"],"names":[],"mappings":"AAeA,0CAA0C;AAC1C,MAAM,MAAM,SAAS,GAAG;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,sCAAsC;AACtC,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,GACd,SAAS,EAAE,CAiCb;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAK/D;AAcD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,GAClB,MAAM,CA6HR"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AFK session report generator.
|
|
3
|
+
*
|
|
4
|
+
* Reads progress.txt and costs.log entries created during the current
|
|
5
|
+
* AFK session and generates a markdown report at `.clancy/session-report.md`.
|
|
6
|
+
*/
|
|
7
|
+
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
import { formatDuration } from '../../../scripts/shared/format/format.js';
|
|
10
|
+
import { parseProgressFile, } from '../../../scripts/shared/progress/progress.js';
|
|
11
|
+
/**
|
|
12
|
+
* Parse costs.log and return entries with ISO timestamp >= the given threshold.
|
|
13
|
+
*
|
|
14
|
+
* Each line is expected to follow the format:
|
|
15
|
+
* `ISO-timestamp | KEY | Nmin | ~N tokens (estimated)`
|
|
16
|
+
*
|
|
17
|
+
* Lines that don't match are silently skipped.
|
|
18
|
+
*
|
|
19
|
+
* @param projectRoot - The project root directory.
|
|
20
|
+
* @param sinceMs - Only include entries with timestamp >= this value (ms since epoch).
|
|
21
|
+
* @returns Parsed cost entries from this session.
|
|
22
|
+
*/
|
|
23
|
+
export function parseCostsLog(projectRoot, sinceMs) {
|
|
24
|
+
const filePath = join(projectRoot, '.clancy', 'costs.log');
|
|
25
|
+
let content;
|
|
26
|
+
try {
|
|
27
|
+
content = readFileSync(filePath, 'utf8');
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
const entries = [];
|
|
33
|
+
for (const line of content.split('\n')) {
|
|
34
|
+
const trimmed = line.trim();
|
|
35
|
+
if (!trimmed)
|
|
36
|
+
continue;
|
|
37
|
+
const parts = trimmed.split(' | ');
|
|
38
|
+
if (parts.length < 4)
|
|
39
|
+
continue;
|
|
40
|
+
const timestamp = parts[0];
|
|
41
|
+
const entryTime = new Date(timestamp).getTime();
|
|
42
|
+
if (Number.isNaN(entryTime) || entryTime < sinceMs)
|
|
43
|
+
continue;
|
|
44
|
+
entries.push({
|
|
45
|
+
timestamp,
|
|
46
|
+
key: parts[1],
|
|
47
|
+
duration: parts[2],
|
|
48
|
+
tokens: parts[3],
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
return entries;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Convert a progress timestamp (`YYYY-MM-DD HH:MM`) to milliseconds since epoch.
|
|
55
|
+
*
|
|
56
|
+
* @param timestamp - The progress file timestamp string.
|
|
57
|
+
* @returns Milliseconds since epoch, or `NaN` if the timestamp is invalid.
|
|
58
|
+
*/
|
|
59
|
+
export function progressTimestampToMs(timestamp) {
|
|
60
|
+
// Progress timestamps are UTC: "YYYY-MM-DD HH:MM"
|
|
61
|
+
// Validate format before parsing to avoid JS Date quirks with garbage input
|
|
62
|
+
if (!/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/.test(timestamp))
|
|
63
|
+
return NaN;
|
|
64
|
+
return new Date(timestamp.replace(' ', 'T') + ':00Z').getTime();
|
|
65
|
+
}
|
|
66
|
+
/** Statuses that indicate a successfully completed ticket. */
|
|
67
|
+
const COMPLETED_STATUSES = new Set([
|
|
68
|
+
'DONE',
|
|
69
|
+
'PR_CREATED',
|
|
70
|
+
'PUSHED',
|
|
71
|
+
'EPIC_PR_CREATED',
|
|
72
|
+
'RESUMED',
|
|
73
|
+
]);
|
|
74
|
+
/** Statuses that indicate a failed/skipped ticket. */
|
|
75
|
+
const FAILED_STATUSES = new Set(['SKIPPED', 'PUSH_FAILED', 'TIME_LIMIT']);
|
|
76
|
+
/**
|
|
77
|
+
* Generate a session report from progress.txt and costs.log entries
|
|
78
|
+
* created during this AFK session.
|
|
79
|
+
*
|
|
80
|
+
* @param projectRoot - The project root directory.
|
|
81
|
+
* @param loopStartTime - When the AFK loop started (Date.now()).
|
|
82
|
+
* @param loopEndTime - When the AFK loop ended.
|
|
83
|
+
* @returns The report markdown string.
|
|
84
|
+
*/
|
|
85
|
+
export function generateSessionReport(projectRoot, loopStartTime, loopEndTime) {
|
|
86
|
+
// 1. Read progress.txt, filter entries with timestamp >= loopStart
|
|
87
|
+
// Round loopStart down to the minute to match progress file precision (YYYY-MM-DD HH:MM)
|
|
88
|
+
const loopStartMinute = Math.floor(loopStartTime / 60000) * 60000;
|
|
89
|
+
const allProgress = parseProgressFile(projectRoot);
|
|
90
|
+
const sessionEntries = allProgress.filter((entry) => {
|
|
91
|
+
const entryMs = progressTimestampToMs(entry.timestamp);
|
|
92
|
+
return !Number.isNaN(entryMs) && entryMs >= loopStartMinute;
|
|
93
|
+
});
|
|
94
|
+
// 2. Read costs.log, filter entries with timestamp >= loopStart
|
|
95
|
+
const costEntries = parseCostsLog(projectRoot, loopStartTime);
|
|
96
|
+
// 3. Build a cost lookup by ticket key
|
|
97
|
+
const costByKey = new Map();
|
|
98
|
+
for (const cost of costEntries) {
|
|
99
|
+
costByKey.set(cost.key, cost);
|
|
100
|
+
}
|
|
101
|
+
// 4. Deduplicate progress entries — keep latest per key (for rework cycles)
|
|
102
|
+
const latestByKey = new Map();
|
|
103
|
+
for (const entry of sessionEntries) {
|
|
104
|
+
latestByKey.set(entry.key, entry);
|
|
105
|
+
}
|
|
106
|
+
// 5. Build session tickets
|
|
107
|
+
const tickets = [];
|
|
108
|
+
for (const entry of latestByKey.values()) {
|
|
109
|
+
const cost = costByKey.get(entry.key);
|
|
110
|
+
tickets.push({
|
|
111
|
+
key: entry.key,
|
|
112
|
+
summary: entry.summary,
|
|
113
|
+
status: entry.status,
|
|
114
|
+
...(entry.prNumber != null && { prNumber: entry.prNumber }),
|
|
115
|
+
...(cost && { duration: cost.duration, tokens: cost.tokens }),
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
// 6. Count completed vs failed
|
|
119
|
+
const completed = tickets.filter((t) => COMPLETED_STATUSES.has(t.status));
|
|
120
|
+
const failed = tickets.filter((t) => FAILED_STATUSES.has(t.status));
|
|
121
|
+
const totalDuration = formatDuration(loopEndTime - loopStartTime);
|
|
122
|
+
// 7. Calculate total estimated tokens
|
|
123
|
+
let totalTokens = 0;
|
|
124
|
+
for (const cost of costEntries) {
|
|
125
|
+
const match = cost.tokens.match(/~(\d[\d,]*)/);
|
|
126
|
+
if (match) {
|
|
127
|
+
totalTokens += parseInt(match[1].replace(/,/g, ''), 10);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// 8. Format the date
|
|
131
|
+
const date = new Date(loopStartTime);
|
|
132
|
+
const dateStr = `${date.getUTCFullYear()}-${String(date.getUTCMonth() + 1).padStart(2, '0')}-${String(date.getUTCDate()).padStart(2, '0')}`;
|
|
133
|
+
// 9. Generate markdown
|
|
134
|
+
const lines = [];
|
|
135
|
+
lines.push(`# AFK Session Report — ${dateStr}`);
|
|
136
|
+
lines.push('');
|
|
137
|
+
lines.push('## Summary');
|
|
138
|
+
lines.push(`- Tickets completed: ${completed.length}`);
|
|
139
|
+
lines.push(`- Tickets failed: ${failed.length}`);
|
|
140
|
+
lines.push(`- Total duration: ${totalDuration}`);
|
|
141
|
+
if (totalTokens > 0) {
|
|
142
|
+
lines.push(`- Estimated token usage: ${totalTokens.toLocaleString('en-US')}`);
|
|
143
|
+
}
|
|
144
|
+
lines.push('');
|
|
145
|
+
lines.push('## Tickets');
|
|
146
|
+
if (tickets.length === 0) {
|
|
147
|
+
lines.push('');
|
|
148
|
+
lines.push('No tickets were processed in this session.');
|
|
149
|
+
}
|
|
150
|
+
for (const ticket of tickets) {
|
|
151
|
+
const isCompleted = COMPLETED_STATUSES.has(ticket.status);
|
|
152
|
+
const icon = isCompleted ? '\u2713' : '\u2717';
|
|
153
|
+
lines.push('');
|
|
154
|
+
lines.push(`### ${icon} ${ticket.key} — ${ticket.summary}`);
|
|
155
|
+
if (ticket.duration) {
|
|
156
|
+
lines.push(`- Duration: ${ticket.duration}`);
|
|
157
|
+
}
|
|
158
|
+
if (ticket.tokens) {
|
|
159
|
+
lines.push(`- Tokens: ${ticket.tokens}`);
|
|
160
|
+
}
|
|
161
|
+
if (ticket.prNumber != null) {
|
|
162
|
+
lines.push(`- PR: #${ticket.prNumber}`);
|
|
163
|
+
}
|
|
164
|
+
lines.push(`- Status: ${ticket.status}`);
|
|
165
|
+
}
|
|
166
|
+
// 10. Next Steps
|
|
167
|
+
const prNumbers = tickets
|
|
168
|
+
.filter((t) => t.prNumber != null)
|
|
169
|
+
.map((t) => `#${t.prNumber}`);
|
|
170
|
+
const skippedKeys = failed.map((t) => t.key);
|
|
171
|
+
if (prNumbers.length > 0 || skippedKeys.length > 0) {
|
|
172
|
+
lines.push('');
|
|
173
|
+
lines.push('## Next Steps');
|
|
174
|
+
if (prNumbers.length > 0) {
|
|
175
|
+
lines.push(`- Review PRs ${prNumbers.join(', ')}`);
|
|
176
|
+
}
|
|
177
|
+
for (const key of skippedKeys) {
|
|
178
|
+
lines.push(`- ${key} needs manual intervention`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
lines.push('');
|
|
182
|
+
const report = lines.join('\n');
|
|
183
|
+
// 11. Write to .clancy/session-report.md (best-effort)
|
|
184
|
+
try {
|
|
185
|
+
const reportPath = join(projectRoot, '.clancy', 'session-report.md');
|
|
186
|
+
mkdirSync(join(projectRoot, '.clancy'), { recursive: true });
|
|
187
|
+
writeFileSync(reportPath, report, 'utf8');
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
// Best-effort — report is still returned for stdout
|
|
191
|
+
}
|
|
192
|
+
return report;
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../../../../src/scripts/afk/report/report.ts"],"names":[],"mappings":"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"}
|
|
@@ -45,16 +45,46 @@ export declare function resolveUsername(token: string, apiBase?: string): Promis
|
|
|
45
45
|
export declare function fetchIssue(token: string, repo: string, label?: string, username?: string): Promise<(Ticket & {
|
|
46
46
|
milestone?: string;
|
|
47
47
|
}) | undefined>;
|
|
48
|
+
/** GitHub issue with optional milestone. */
|
|
49
|
+
export type GitHubTicket = Ticket & {
|
|
50
|
+
milestone?: string;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Fetch multiple candidate issues from GitHub Issues.
|
|
54
|
+
*
|
|
55
|
+
* @param token - The GitHub personal access token.
|
|
56
|
+
* @param repo - The repository in `owner/repo` format.
|
|
57
|
+
* @param label - Optional label to filter issues.
|
|
58
|
+
* @param username - The GitHub username for assignee filtering.
|
|
59
|
+
* @param excludeHitl - If `true`, excludes issues with the `clancy:hitl` label (client-side).
|
|
60
|
+
* @param limit - Maximum number of results to return (default: 5).
|
|
61
|
+
* @returns Array of fetched tickets (may be empty).
|
|
62
|
+
*/
|
|
63
|
+
export declare function fetchIssues(token: string, repo: string, label?: string, username?: string, excludeHitl?: boolean, limit?: number): Promise<GitHubTicket[]>;
|
|
64
|
+
/**
|
|
65
|
+
* Check whether a GitHub issue is blocked by unresolved blockers.
|
|
66
|
+
*
|
|
67
|
+
* Parses the issue body for `Blocked by #N` lines and checks if any
|
|
68
|
+
* of those issues are still open.
|
|
69
|
+
*
|
|
70
|
+
* @param token - The GitHub personal access token.
|
|
71
|
+
* @param repo - The repository in `owner/repo` format.
|
|
72
|
+
* @param issueNumber - The issue number to check.
|
|
73
|
+
* @param body - The issue body text.
|
|
74
|
+
* @returns `true` if any blocker is unresolved, `false` otherwise.
|
|
75
|
+
*/
|
|
76
|
+
export declare function fetchBlockerStatus(token: string, repo: string, issueNumber: number, body: string): Promise<boolean>;
|
|
48
77
|
/** Result of checking children status for an epic/milestone. */
|
|
49
78
|
export type ChildrenStatus = {
|
|
50
79
|
total: number;
|
|
51
80
|
incomplete: number;
|
|
52
81
|
};
|
|
53
82
|
/**
|
|
54
|
-
* Fetch the children status of a GitHub parent issue.
|
|
83
|
+
* Fetch the children status of a GitHub parent issue (dual-mode).
|
|
55
84
|
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
85
|
+
* Tries the `Epic: #{parentNumber}` text convention first. If no results,
|
|
86
|
+
* falls back to the native `Parent: #{parentNumber}` convention for
|
|
87
|
+
* backward compatibility with pre-v0.6.0 children.
|
|
58
88
|
*
|
|
59
89
|
* @param token - The GitHub personal access token.
|
|
60
90
|
* @param repo - The repository in `owner/repo` format.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../../../src/scripts/board/github/github.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAY/C,4DAA4D;AAC5D,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,UAAU,CAAC,CAWrB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,CAmCjB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,CAAC,MAAM,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,SAAS,CAAC,
|
|
1
|
+
{"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../../../src/scripts/board/github/github.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAY/C,4DAA4D;AAC5D,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,UAAU,CAAC,CAWrB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,CAmCjB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,CAAC,MAAM,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,SAAS,CAAC,CAGxD;AAED,4CAA4C;AAC5C,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3D;;;;;;;;;;GAUG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,MAAM,EACjB,WAAW,CAAC,EAAE,OAAO,EACrB,KAAK,SAAI,GACR,OAAO,CAAC,YAAY,EAAE,CAAC,CA6DzB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,OAAO,CAAC,CAoClB;AAED,gEAAgE;AAChE,MAAM,MAAM,cAAc,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnE;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAsBrC;AA6CD;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,OAAO,CAAC,CAoBlB"}
|
|
@@ -96,6 +96,21 @@ export async function resolveUsername(token, apiBase) {
|
|
|
96
96
|
* @returns The fetched ticket with optional milestone, or `undefined` if none available.
|
|
97
97
|
*/
|
|
98
98
|
export async function fetchIssue(token, repo, label, username) {
|
|
99
|
+
const results = await fetchIssues(token, repo, label, username, false, 1);
|
|
100
|
+
return results[0];
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Fetch multiple candidate issues from GitHub Issues.
|
|
104
|
+
*
|
|
105
|
+
* @param token - The GitHub personal access token.
|
|
106
|
+
* @param repo - The repository in `owner/repo` format.
|
|
107
|
+
* @param label - Optional label to filter issues.
|
|
108
|
+
* @param username - The GitHub username for assignee filtering.
|
|
109
|
+
* @param excludeHitl - If `true`, excludes issues with the `clancy:hitl` label (client-side).
|
|
110
|
+
* @param limit - Maximum number of results to return (default: 5).
|
|
111
|
+
* @returns Array of fetched tickets (may be empty).
|
|
112
|
+
*/
|
|
113
|
+
export async function fetchIssues(token, repo, label, username, excludeHitl, limit = 5) {
|
|
99
114
|
let response;
|
|
100
115
|
const params = new URLSearchParams({
|
|
101
116
|
state: 'open',
|
|
@@ -111,11 +126,11 @@ export async function fetchIssue(token, repo, label, username) {
|
|
|
111
126
|
}
|
|
112
127
|
catch (err) {
|
|
113
128
|
console.warn(`⚠ GitHub API request failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
114
|
-
return
|
|
129
|
+
return [];
|
|
115
130
|
}
|
|
116
131
|
if (!response.ok) {
|
|
117
132
|
console.warn(`⚠ GitHub API returned HTTP ${response.status}`);
|
|
118
|
-
return
|
|
133
|
+
return [];
|
|
119
134
|
}
|
|
120
135
|
let json;
|
|
121
136
|
try {
|
|
@@ -123,31 +138,77 @@ export async function fetchIssue(token, repo, label, username) {
|
|
|
123
138
|
}
|
|
124
139
|
catch {
|
|
125
140
|
console.warn('⚠ GitHub API returned invalid JSON');
|
|
126
|
-
return
|
|
141
|
+
return [];
|
|
127
142
|
}
|
|
128
143
|
const parsed = githubIssuesResponseSchema.safeParse(json);
|
|
129
144
|
if (!parsed.success) {
|
|
130
145
|
console.warn(`⚠ Unexpected GitHub response shape: ${parsed.error.message}`);
|
|
131
|
-
return
|
|
146
|
+
return [];
|
|
132
147
|
}
|
|
133
148
|
// Filter out pull requests
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
149
|
+
let issues = parsed.data.filter((item) => !item.pull_request);
|
|
150
|
+
// HITL/AFK filtering: exclude issues with clancy:hitl label
|
|
151
|
+
// GitHub Issues API doesn't support label exclusion natively, so filter client-side.
|
|
152
|
+
if (excludeHitl) {
|
|
153
|
+
issues = issues.filter((issue) => !issue.labels?.some((l) => l.name === 'clancy:hitl'));
|
|
154
|
+
}
|
|
155
|
+
return issues.slice(0, limit).map((issue) => ({
|
|
139
156
|
key: `#${issue.number}`,
|
|
140
157
|
title: issue.title,
|
|
141
158
|
description: issue.body ?? '',
|
|
142
159
|
provider: 'github',
|
|
143
160
|
milestone: issue.milestone?.title,
|
|
144
|
-
};
|
|
161
|
+
}));
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Check whether a GitHub issue is blocked by unresolved blockers.
|
|
165
|
+
*
|
|
166
|
+
* Parses the issue body for `Blocked by #N` lines and checks if any
|
|
167
|
+
* of those issues are still open.
|
|
168
|
+
*
|
|
169
|
+
* @param token - The GitHub personal access token.
|
|
170
|
+
* @param repo - The repository in `owner/repo` format.
|
|
171
|
+
* @param issueNumber - The issue number to check.
|
|
172
|
+
* @param body - The issue body text.
|
|
173
|
+
* @returns `true` if any blocker is unresolved, `false` otherwise.
|
|
174
|
+
*/
|
|
175
|
+
export async function fetchBlockerStatus(token, repo, issueNumber, body) {
|
|
176
|
+
if (!isValidRepo(repo))
|
|
177
|
+
return false;
|
|
178
|
+
// Parse "Blocked by #N" references from the body
|
|
179
|
+
const blockerPattern = /Blocked by #(\d+)/gi;
|
|
180
|
+
const blockerNumbers = new Set();
|
|
181
|
+
let match;
|
|
182
|
+
while ((match = blockerPattern.exec(body)) !== null) {
|
|
183
|
+
const num = parseInt(match[1], 10);
|
|
184
|
+
if (!Number.isNaN(num) && num !== issueNumber) {
|
|
185
|
+
blockerNumbers.add(num);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (!blockerNumbers.size)
|
|
189
|
+
return false;
|
|
190
|
+
try {
|
|
191
|
+
for (const blockerNum of blockerNumbers) {
|
|
192
|
+
const response = await fetch(`${GITHUB_API}/repos/${repo}/issues/${blockerNum}`, { headers: githubHeaders(token) });
|
|
193
|
+
if (!response.ok)
|
|
194
|
+
continue;
|
|
195
|
+
const json = (await response.json());
|
|
196
|
+
// Short-circuit: one unresolved blocker is enough
|
|
197
|
+
if (json.state !== 'closed')
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
145
205
|
}
|
|
146
206
|
/**
|
|
147
|
-
* Fetch the children status of a GitHub parent issue.
|
|
207
|
+
* Fetch the children status of a GitHub parent issue (dual-mode).
|
|
148
208
|
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
209
|
+
* Tries the `Epic: #{parentNumber}` text convention first. If no results,
|
|
210
|
+
* falls back to the native `Parent: #{parentNumber}` convention for
|
|
211
|
+
* backward compatibility with pre-v0.6.0 children.
|
|
151
212
|
*
|
|
152
213
|
* @param token - The GitHub personal access token.
|
|
153
214
|
* @param repo - The repository in `owner/repo` format.
|
|
@@ -158,25 +219,49 @@ export async function fetchChildrenStatus(token, repo, parentNumber) {
|
|
|
158
219
|
if (!isValidRepo(repo))
|
|
159
220
|
return undefined;
|
|
160
221
|
try {
|
|
161
|
-
//
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
if (!allResponse.ok)
|
|
168
|
-
return undefined;
|
|
169
|
-
const allIssues = (await allResponse.json());
|
|
170
|
-
const parentRef = `Parent: #${parentNumber}`;
|
|
171
|
-
const children = allIssues.filter((issue) => !issue.pull_request && issue.body && issue.body.includes(parentRef));
|
|
172
|
-
const total = children.length;
|
|
173
|
-
const incomplete = children.filter((c) => c.state === 'open').length;
|
|
174
|
-
return { total, incomplete };
|
|
222
|
+
// Mode 1: Try Epic: text convention
|
|
223
|
+
const epicTextResult = await fetchChildrenByBodyRef(token, repo, `Epic: #${parentNumber}`);
|
|
224
|
+
if (epicTextResult && epicTextResult.total > 0)
|
|
225
|
+
return epicTextResult;
|
|
226
|
+
// Mode 2: Fall back to native Parent: convention
|
|
227
|
+
return await fetchChildrenByBodyRef(token, repo, `Parent: #${parentNumber}`);
|
|
175
228
|
}
|
|
176
229
|
catch {
|
|
177
230
|
return undefined;
|
|
178
231
|
}
|
|
179
232
|
}
|
|
233
|
+
/**
|
|
234
|
+
* Fetch children status by searching for a body reference string.
|
|
235
|
+
*
|
|
236
|
+
* @param token - The GitHub personal access token.
|
|
237
|
+
* @param repo - The repository in `owner/repo` format.
|
|
238
|
+
* @param bodyRef - The body reference string to search for.
|
|
239
|
+
* @returns The children status, or `undefined` on failure.
|
|
240
|
+
*/
|
|
241
|
+
async function fetchChildrenByBodyRef(token, repo, bodyRef) {
|
|
242
|
+
// Use GitHub Search API with total_count for accurate counts.
|
|
243
|
+
// Two queries: one for all children, one for open (incomplete) children.
|
|
244
|
+
const headers = githubHeaders(token);
|
|
245
|
+
const allQuery = `"${bodyRef}" repo:${repo} is:issue`;
|
|
246
|
+
const allParams = new URLSearchParams({ q: allQuery, per_page: '1' });
|
|
247
|
+
const allResponse = await fetch(`${GITHUB_API}/search/issues?${allParams}`, {
|
|
248
|
+
headers,
|
|
249
|
+
});
|
|
250
|
+
if (!allResponse.ok)
|
|
251
|
+
return undefined;
|
|
252
|
+
const allResult = (await allResponse.json());
|
|
253
|
+
const total = allResult.total_count ?? 0;
|
|
254
|
+
if (total === 0)
|
|
255
|
+
return { total: 0, incomplete: 0 };
|
|
256
|
+
const openQuery = `"${bodyRef}" repo:${repo} is:issue is:open`;
|
|
257
|
+
const openParams = new URLSearchParams({ q: openQuery, per_page: '1' });
|
|
258
|
+
const openResponse = await fetch(`${GITHUB_API}/search/issues?${openParams}`, { headers });
|
|
259
|
+
if (!openResponse.ok)
|
|
260
|
+
return { total, incomplete: total }; // assume all open on failure
|
|
261
|
+
const openResult = (await openResponse.json());
|
|
262
|
+
const incomplete = openResult.total_count ?? 0;
|
|
263
|
+
return { total, incomplete };
|
|
264
|
+
}
|
|
180
265
|
/**
|
|
181
266
|
* Close a GitHub issue.
|
|
182
267
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"github.js","sourceRoot":"","sources":["../../../../src/scripts/board/github/github.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"github.js","sourceRoot":"","sources":["../../../../src/scripts/board/github/github.ts"],"names":[],"mappings":"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"}
|