devharness 0.9.3 → 0.9.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/build/block-events.d.ts +42 -0
- package/build/block-events.d.ts.map +1 -0
- package/build/block-events.js +67 -0
- package/build/block-events.js.map +1 -0
- package/build/block-events.test.d.ts +2 -0
- package/build/block-events.test.d.ts.map +1 -0
- package/build/block-events.test.js +131 -0
- package/build/block-events.test.js.map +1 -0
- package/build/command-recorder.d.ts +2 -0
- package/build/command-recorder.d.ts.map +1 -1
- package/build/command-recorder.js +4 -0
- package/build/command-recorder.js.map +1 -1
- package/build/config.d.ts +9 -0
- package/build/config.d.ts.map +1 -1
- package/build/config.js +10 -0
- package/build/config.js.map +1 -1
- package/build/dashboard/dashboard-hub.js +2 -2
- package/build/dashboard/dashboard-hub.js.map +1 -1
- package/build/github/gh-cli.d.ts +41 -0
- package/build/github/gh-cli.d.ts.map +1 -0
- package/build/github/gh-cli.js +147 -0
- package/build/github/gh-cli.js.map +1 -0
- package/build/github/gh-cli.test.d.ts +2 -0
- package/build/github/gh-cli.test.d.ts.map +1 -0
- package/build/github/gh-cli.test.js +145 -0
- package/build/github/gh-cli.test.js.map +1 -0
- package/build/github/gh-issues.d.ts +105 -0
- package/build/github/gh-issues.d.ts.map +1 -0
- package/build/github/gh-issues.js +199 -0
- package/build/github/gh-issues.js.map +1 -0
- package/build/github/gh-issues.test.d.ts +2 -0
- package/build/github/gh-issues.test.d.ts.map +1 -0
- package/build/github/gh-issues.test.js +118 -0
- package/build/github/gh-issues.test.js.map +1 -0
- package/build/github/issue-actions.d.ts +34 -0
- package/build/github/issue-actions.d.ts.map +1 -0
- package/build/github/issue-actions.js +530 -0
- package/build/github/issue-actions.js.map +1 -0
- package/build/github/issue-actions.test.d.ts +2 -0
- package/build/github/issue-actions.test.d.ts.map +1 -0
- package/build/github/issue-actions.test.js +555 -0
- package/build/github/issue-actions.test.js.map +1 -0
- package/build/github/issue-body.d.ts +179 -0
- package/build/github/issue-body.d.ts.map +1 -0
- package/build/github/issue-body.js +181 -0
- package/build/github/issue-body.js.map +1 -0
- package/build/github/issue-body.test.d.ts +2 -0
- package/build/github/issue-body.test.d.ts.map +1 -0
- package/build/github/issue-body.test.js +157 -0
- package/build/github/issue-body.test.js.map +1 -0
- package/build/helpers/paths.d.ts +7 -0
- package/build/helpers/paths.d.ts.map +1 -1
- package/build/helpers/paths.js +10 -1
- package/build/helpers/paths.js.map +1 -1
- package/build/index.js +37 -3
- package/build/index.js.map +1 -1
- package/build/issue-tracker.d.ts +30 -0
- package/build/issue-tracker.d.ts.map +1 -1
- package/build/issue-tracker.js +91 -1
- package/build/issue-tracker.js.map +1 -1
- package/build/issue-tracker.test.js +76 -1
- package/build/issue-tracker.test.js.map +1 -1
- package/build/server-block-cleanup.test.d.ts +2 -0
- package/build/server-block-cleanup.test.d.ts.map +1 -0
- package/build/server-block-cleanup.test.js +143 -0
- package/build/server-block-cleanup.test.js.map +1 -0
- package/build/server-manager.d.ts +8 -0
- package/build/server-manager.d.ts.map +1 -1
- package/build/server-manager.js +49 -0
- package/build/server-manager.js.map +1 -1
- package/build/startup-gate.d.ts +29 -0
- package/build/startup-gate.d.ts.map +1 -0
- package/build/startup-gate.js +49 -0
- package/build/startup-gate.js.map +1 -0
- package/build/startup-gate.test.d.ts +2 -0
- package/build/startup-gate.test.d.ts.map +1 -0
- package/build/startup-gate.test.js +73 -0
- package/build/startup-gate.test.js.map +1 -0
- package/build/tool-response.d.ts +29 -0
- package/build/tool-response.d.ts.map +1 -1
- package/build/tool-response.js +46 -1
- package/build/tool-response.js.map +1 -1
- package/build/tools/assert-tools.d.ts +3 -3
- package/build/tools/breakpoint-tools.d.ts +3 -3
- package/build/tools/config-tools.d.ts +3 -3
- package/build/tools/console-tools.d.ts +9 -9
- package/build/tools/content-tools.d.ts +3 -3
- package/build/tools/input-tools.d.ts +9 -9
- package/build/tools/issues-tools.d.ts +32 -8
- package/build/tools/issues-tools.d.ts.map +1 -1
- package/build/tools/issues-tools.js +55 -5
- package/build/tools/issues-tools.js.map +1 -1
- package/build/tools/page-tools.d.ts +3 -3
- package/build/tools/replay-sequence-reload.test.js +23 -7
- package/build/tools/replay-sequence-reload.test.js.map +1 -1
- package/build/tools/replay-tools.d.ts +9 -9
- package/build/tools/request-tools.d.ts +3 -3
- package/build/tools/server-tools.d.ts +9 -9
- package/build/tools/storage-tools.d.ts +3 -3
- package/build/tools/wait-tools.d.ts +6 -6
- package/docs/instructions.md +26 -1
- package/docs/messages.md +264 -0
- package/package.json +1 -1
- package/plugin/skills/devharness/SKILL.md +18 -1
- package/plugin/skills/devharness/references/tool-categories.md +8 -1
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed `gh` operations for issues, and the pure policy that decides what a
|
|
3
|
+
* sync should do. The policy is separated so the truth table is testable
|
|
4
|
+
* without a subprocess.
|
|
5
|
+
*/
|
|
6
|
+
import { createHash } from 'crypto';
|
|
7
|
+
import { runGh, runGhJson } from './gh-cli.js';
|
|
8
|
+
import { completedStatusFor, isCompletedStatus, } from '../issue-tracker.js';
|
|
9
|
+
function repoArgs(repo) {
|
|
10
|
+
return repo ? ['--repo', repo] : [];
|
|
11
|
+
}
|
|
12
|
+
function normaliseLabels(raw) {
|
|
13
|
+
if (!Array.isArray(raw))
|
|
14
|
+
return [];
|
|
15
|
+
return raw
|
|
16
|
+
.map(l => (typeof l === 'string' ? l : l?.name))
|
|
17
|
+
.filter((l) => typeof l === 'string' && l.length > 0);
|
|
18
|
+
}
|
|
19
|
+
export async function ghRepoName(repo, opts) {
|
|
20
|
+
if (repo)
|
|
21
|
+
return repo;
|
|
22
|
+
const result = await runGhJson(['repo', 'view', '--json', 'nameWithOwner'], opts);
|
|
23
|
+
return result.nameWithOwner;
|
|
24
|
+
}
|
|
25
|
+
export async function ghExistingLabels(repo, opts) {
|
|
26
|
+
const raw = await runGhJson(['label', 'list', '--limit', '200', '--json', 'name', ...repoArgs(repo)], opts);
|
|
27
|
+
return new Set(raw.map(l => l.name));
|
|
28
|
+
}
|
|
29
|
+
export async function ghCreateLabel(name, repo, opts) {
|
|
30
|
+
await runGh(['label', 'create', name, ...repoArgs(repo)], opts);
|
|
31
|
+
}
|
|
32
|
+
/** `gh issue create` has no --json; it prints the URL. */
|
|
33
|
+
export async function ghCreateIssue(params, opts) {
|
|
34
|
+
const args = ['issue', 'create', '--title', params.title, '--body-file', '-', ...repoArgs(params.repo)];
|
|
35
|
+
for (const label of params.labels)
|
|
36
|
+
args.push('--label', label);
|
|
37
|
+
const stdout = await runGh(args, { ...opts, stdin: params.body });
|
|
38
|
+
const match = stdout.match(/\/issues\/(\d+)\s*$/m);
|
|
39
|
+
const url = stdout.trim().split(/\s+/).pop() ?? stdout.trim();
|
|
40
|
+
// The issue exists either way - an unparseable number is a stamping
|
|
41
|
+
// problem, never a create failure.
|
|
42
|
+
return match ? { number: parseInt(match[1], 10), url } : { number: null, url, raw: stdout };
|
|
43
|
+
}
|
|
44
|
+
export async function ghViewIssue(number, repo, opts) {
|
|
45
|
+
const raw = await runGhJson([
|
|
46
|
+
'issue', 'view', String(number),
|
|
47
|
+
'--json', 'number,title,body,author,state,stateReason,labels,updatedAt,url,comments',
|
|
48
|
+
...repoArgs(repo),
|
|
49
|
+
], opts);
|
|
50
|
+
return {
|
|
51
|
+
number: raw.number,
|
|
52
|
+
title: raw.title ?? '',
|
|
53
|
+
body: raw.body ?? '',
|
|
54
|
+
author: raw.author?.login ?? '',
|
|
55
|
+
state: raw.state === 'CLOSED' ? 'CLOSED' : 'OPEN',
|
|
56
|
+
stateReason: raw.stateReason ?? null,
|
|
57
|
+
labels: normaliseLabels(raw.labels),
|
|
58
|
+
updatedAt: raw.updatedAt,
|
|
59
|
+
url: raw.url,
|
|
60
|
+
comments: (raw.comments ?? []).map((c) => ({
|
|
61
|
+
id: String(c.id ?? c.url ?? ''),
|
|
62
|
+
body: c.body ?? '',
|
|
63
|
+
author: c.author?.login ?? '',
|
|
64
|
+
createdAt: c.createdAt ?? '',
|
|
65
|
+
})),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/** The login gh is authenticated as - the yardstick for "did someone else
|
|
69
|
+
* write this". */
|
|
70
|
+
export async function ghCurrentUser(opts) {
|
|
71
|
+
const out = await runGh(['api', 'user', '--jq', '.login'], opts);
|
|
72
|
+
return out.trim();
|
|
73
|
+
}
|
|
74
|
+
export async function ghListIssues(repo, opts) {
|
|
75
|
+
const raw = await runGhJson([
|
|
76
|
+
'issue', 'list', '--state', 'all', '--limit', '200',
|
|
77
|
+
'--json', 'number,state,stateReason,labels,updatedAt,url',
|
|
78
|
+
...repoArgs(repo),
|
|
79
|
+
], opts);
|
|
80
|
+
return raw.map(r => ({
|
|
81
|
+
number: r.number,
|
|
82
|
+
state: r.state === 'CLOSED' ? 'CLOSED' : 'OPEN',
|
|
83
|
+
stateReason: r.stateReason ?? null,
|
|
84
|
+
labels: normaliseLabels(r.labels),
|
|
85
|
+
updatedAt: r.updatedAt,
|
|
86
|
+
url: r.url,
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
export async function ghEditBody(number, body, repo, opts) {
|
|
90
|
+
await runGh(['issue', 'edit', String(number), '--body-file', '-', ...repoArgs(repo)], { ...opts, stdin: body });
|
|
91
|
+
}
|
|
92
|
+
export async function ghAddComment(number, body, repo, opts) {
|
|
93
|
+
await runGh(['issue', 'comment', String(number), '--body-file', '-', ...repoArgs(repo)], { ...opts, stdin: body });
|
|
94
|
+
}
|
|
95
|
+
export async function ghCloseIssue(number, reason, repo, opts) {
|
|
96
|
+
const ghReason = reason === 'not_planned' ? 'not planned' : reason;
|
|
97
|
+
await runGh(['issue', 'close', String(number), '--reason', ghReason, ...repoArgs(repo)], opts);
|
|
98
|
+
}
|
|
99
|
+
// =============================================================================
|
|
100
|
+
// Comment identity
|
|
101
|
+
// =============================================================================
|
|
102
|
+
/** Hidden marker naming the upstream comment a local comment came from. It
|
|
103
|
+
* lives inside the comment text, so it needs no schema change and survives
|
|
104
|
+
* the existing parse/serialize round trip. */
|
|
105
|
+
const GH_COMMENT_MARKER_RE = /^<!-- gh: (.+?) -->\r?\n?/;
|
|
106
|
+
export function markComment(id, body) {
|
|
107
|
+
return `<!-- gh: ${id} -->\n${body}`;
|
|
108
|
+
}
|
|
109
|
+
export function commentGithubId(text) {
|
|
110
|
+
const match = text.match(GH_COMMENT_MARKER_RE);
|
|
111
|
+
return match ? match[1] : null;
|
|
112
|
+
}
|
|
113
|
+
export function stripCommentMarker(text) {
|
|
114
|
+
return text.replace(GH_COMMENT_MARKER_RE, '');
|
|
115
|
+
}
|
|
116
|
+
/** The `<!-- devharness: local #N -->` marker publish appends to the GitHub
|
|
117
|
+
* body. It is upstream-only metadata: strip it from anything stored or
|
|
118
|
+
* hashed locally, or a pull-then-push cycle accretes one marker per sync. */
|
|
119
|
+
const LOCAL_MARKER_RE = /\n*<!--\s*devharness: local #\d+\s*-->/g;
|
|
120
|
+
export function stripLocalMarker(body) {
|
|
121
|
+
return body.replace(LOCAL_MARKER_RE, '');
|
|
122
|
+
}
|
|
123
|
+
// =============================================================================
|
|
124
|
+
// Sync policy (pure)
|
|
125
|
+
// =============================================================================
|
|
126
|
+
export function bodyHash(body) {
|
|
127
|
+
return createHash('sha256').update(body, 'utf8').digest('hex').slice(0, 16);
|
|
128
|
+
}
|
|
129
|
+
export function closedReasonFrom(stateReason) {
|
|
130
|
+
const value = (stateReason ?? '').toLowerCase().replace(/\s+/g, '_');
|
|
131
|
+
if (value === 'not_planned' || value === 'duplicate')
|
|
132
|
+
return value;
|
|
133
|
+
return 'completed';
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Which side moved since the two last agreed.
|
|
137
|
+
*
|
|
138
|
+
* With no baseline this is a first sync: adopt whichever side has content
|
|
139
|
+
* rather than reporting a conflict on an issue nobody has actually edited.
|
|
140
|
+
*/
|
|
141
|
+
export function classifySync(local, remote, strippedLocalBody) {
|
|
142
|
+
if (!remote) {
|
|
143
|
+
return { action: 'missing-upstream', localChanged: false, remoteChanged: false, firstSync: false };
|
|
144
|
+
}
|
|
145
|
+
const firstSync = !local.githubSyncedAt || !local.githubBodyHash;
|
|
146
|
+
if (firstSync) {
|
|
147
|
+
return { action: 'pull', localChanged: false, remoteChanged: true, firstSync: true };
|
|
148
|
+
}
|
|
149
|
+
const localChanged = bodyHash(strippedLocalBody) !== local.githubBodyHash;
|
|
150
|
+
const remoteChanged = new Date(remote.updatedAt).getTime() > local.githubSyncedAt.getTime();
|
|
151
|
+
let action = 'none';
|
|
152
|
+
if (localChanged && remoteChanged)
|
|
153
|
+
action = 'conflict';
|
|
154
|
+
else if (remoteChanged)
|
|
155
|
+
action = 'pull';
|
|
156
|
+
else if (localChanged)
|
|
157
|
+
action = 'push';
|
|
158
|
+
return { action, localChanged, remoteChanged, firstSync: false };
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* How local status and upstream state reconcile.
|
|
162
|
+
*
|
|
163
|
+
* devharness closes issues upstream but never reopens them; GitHub can do
|
|
164
|
+
* both locally. That asymmetry is what keeps an automated sync from undoing
|
|
165
|
+
* a human's decision on a public issue.
|
|
166
|
+
*/
|
|
167
|
+
export function resolveStatus(local, remote, now) {
|
|
168
|
+
const localClosed = isCompletedStatus(local.status);
|
|
169
|
+
if (remote.state === 'CLOSED') {
|
|
170
|
+
const closedReason = closedReasonFrom(remote.stateReason);
|
|
171
|
+
if (localClosed)
|
|
172
|
+
return { closedReason };
|
|
173
|
+
return { status: completedStatusFor(local.type), closedReason, resolvedAt: now };
|
|
174
|
+
}
|
|
175
|
+
// Upstream is open.
|
|
176
|
+
if (!localClosed)
|
|
177
|
+
return {};
|
|
178
|
+
// Closed here and open there. If we had recorded a close, GitHub reopened
|
|
179
|
+
// it - follow. Otherwise this close has not reached GitHub yet.
|
|
180
|
+
if (local.closedReason) {
|
|
181
|
+
return {
|
|
182
|
+
status: local.startedAt ? 'in_progress' : 'acknowledged',
|
|
183
|
+
closedReason: undefined,
|
|
184
|
+
resolvedAt: undefined,
|
|
185
|
+
reopened: true,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
return { closeUpstream: 'completed' };
|
|
189
|
+
}
|
|
190
|
+
/** Upstream labels are added, never removed - a replace would delete exactly
|
|
191
|
+
* the local-only tags that carry the triage meaning. */
|
|
192
|
+
export function unionLabels(local, remote) {
|
|
193
|
+
const merged = [...local];
|
|
194
|
+
for (const label of remote)
|
|
195
|
+
if (!merged.includes(label))
|
|
196
|
+
merged.push(label);
|
|
197
|
+
return merged;
|
|
198
|
+
}
|
|
199
|
+
//# sourceMappingURL=gh-issues.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gh-issues.js","sourceRoot":"","sources":["../../src/github/gh-issues.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gh-issues.test.d.ts","sourceRoot":"","sources":["../../src/github/gh-issues.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { classifySync, resolveStatus, unionLabels, bodyHash, closedReasonFrom, markComment, commentGithubId, stripCommentMarker, } from './gh-issues.js';
|
|
3
|
+
const SYNCED_AT = new Date('2026-08-01T00:00:00.000Z');
|
|
4
|
+
const NOW = new Date('2026-08-11T00:00:00.000Z');
|
|
5
|
+
function local(body, overrides = {}) {
|
|
6
|
+
return { body, githubBodyHash: bodyHash(body), githubSyncedAt: SYNCED_AT, ...overrides };
|
|
7
|
+
}
|
|
8
|
+
describe('classifySync', () => {
|
|
9
|
+
it('does nothing when neither side moved', () => {
|
|
10
|
+
const issue = local('same');
|
|
11
|
+
const result = classifySync(issue, { updatedAt: '2026-07-01T00:00:00.000Z' }, 'same');
|
|
12
|
+
expect(result.action).toBe('none');
|
|
13
|
+
});
|
|
14
|
+
it('pulls when only the remote moved', () => {
|
|
15
|
+
const issue = local('same');
|
|
16
|
+
const result = classifySync(issue, { updatedAt: '2026-08-05T00:00:00.000Z' }, 'same');
|
|
17
|
+
expect(result).toMatchObject({ action: 'pull', remoteChanged: true, localChanged: false });
|
|
18
|
+
});
|
|
19
|
+
it('pushes when only the local moved', () => {
|
|
20
|
+
const issue = local('original');
|
|
21
|
+
const result = classifySync(issue, { updatedAt: '2026-07-01T00:00:00.000Z' }, 'edited locally');
|
|
22
|
+
expect(result).toMatchObject({ action: 'push', localChanged: true, remoteChanged: false });
|
|
23
|
+
});
|
|
24
|
+
it('reports a conflict when both moved', () => {
|
|
25
|
+
const issue = local('original');
|
|
26
|
+
const result = classifySync(issue, { updatedAt: '2026-08-05T00:00:00.000Z' }, 'edited locally');
|
|
27
|
+
expect(result).toMatchObject({ action: 'conflict', localChanged: true, remoteChanged: true });
|
|
28
|
+
});
|
|
29
|
+
it('adopts rather than conflicting on a first sync', () => {
|
|
30
|
+
// No baseline: the twelve issues stamped by hand are all in this state,
|
|
31
|
+
// and none of them should come back as a conflict.
|
|
32
|
+
const issue = { body: 'anything', githubBodyHash: undefined, githubSyncedAt: undefined };
|
|
33
|
+
const result = classifySync(issue, { updatedAt: '2026-08-05T00:00:00.000Z' }, 'anything');
|
|
34
|
+
expect(result).toMatchObject({ action: 'pull', firstSync: true });
|
|
35
|
+
});
|
|
36
|
+
it('reports missing-upstream when the number is gone', () => {
|
|
37
|
+
expect(classifySync(local('x'), undefined, 'x').action).toBe('missing-upstream');
|
|
38
|
+
});
|
|
39
|
+
it('ignores the sequence block, which is a projection not a local edit', () => {
|
|
40
|
+
// The caller strips the block before hashing; publishing must not make
|
|
41
|
+
// the next sync think the body changed.
|
|
42
|
+
const prose = '## Steps\n\nDo the thing.';
|
|
43
|
+
const issue = local(prose);
|
|
44
|
+
expect(classifySync(issue, { updatedAt: '2026-07-01T00:00:00.000Z' }, prose).action).toBe('none');
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
describe('resolveStatus', () => {
|
|
48
|
+
const openLocal = { type: 'bug', status: 'acknowledged', closedReason: undefined, startedAt: undefined, resolvedAt: undefined };
|
|
49
|
+
const closedLocal = { type: 'bug', status: 'fixed', closedReason: 'completed', startedAt: undefined, resolvedAt: new Date() };
|
|
50
|
+
it('closes locally when upstream is closed', () => {
|
|
51
|
+
const result = resolveStatus(openLocal, { state: 'CLOSED', stateReason: 'COMPLETED' }, NOW);
|
|
52
|
+
expect(result).toMatchObject({ status: 'fixed', closedReason: 'completed', resolvedAt: NOW });
|
|
53
|
+
});
|
|
54
|
+
it('maps a feature to implemented, not fixed', () => {
|
|
55
|
+
const result = resolveStatus({ ...openLocal, type: 'feature' }, { state: 'CLOSED', stateReason: 'COMPLETED' }, NOW);
|
|
56
|
+
expect(result.status).toBe('implemented');
|
|
57
|
+
});
|
|
58
|
+
it('copies not planned and duplicate through verbatim', () => {
|
|
59
|
+
expect(resolveStatus(openLocal, { state: 'CLOSED', stateReason: 'NOT_PLANNED' }, NOW).closedReason).toBe('not_planned');
|
|
60
|
+
expect(resolveStatus(openLocal, { state: 'CLOSED', stateReason: 'DUPLICATE' }, NOW).closedReason).toBe('duplicate');
|
|
61
|
+
});
|
|
62
|
+
it('leaves an open issue alone when upstream is open', () => {
|
|
63
|
+
expect(resolveStatus(openLocal, { state: 'OPEN', stateReason: null }, NOW)).toEqual({});
|
|
64
|
+
});
|
|
65
|
+
it('asks to close upstream when closed here but open there and never synced closed', () => {
|
|
66
|
+
const notYetPushed = { ...closedLocal, closedReason: undefined };
|
|
67
|
+
expect(resolveStatus(notYetPushed, { state: 'OPEN', stateReason: null }, NOW))
|
|
68
|
+
.toMatchObject({ closeUpstream: 'completed' });
|
|
69
|
+
});
|
|
70
|
+
it('follows a reopen from GitHub and clears the resolution', () => {
|
|
71
|
+
const result = resolveStatus(closedLocal, { state: 'OPEN', stateReason: null }, NOW);
|
|
72
|
+
expect(result).toMatchObject({ status: 'acknowledged', reopened: true });
|
|
73
|
+
expect(result.closedReason).toBeUndefined();
|
|
74
|
+
expect(result.resolvedAt).toBeUndefined();
|
|
75
|
+
// Never the other way round: a reopen must not become a close upstream.
|
|
76
|
+
expect(result.closeUpstream).toBeUndefined();
|
|
77
|
+
});
|
|
78
|
+
it('reopens to in_progress when work had already started', () => {
|
|
79
|
+
const result = resolveStatus({ ...closedLocal, startedAt: new Date() }, { state: 'OPEN', stateReason: null }, NOW);
|
|
80
|
+
expect(result.status).toBe('in_progress');
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
describe('unionLabels', () => {
|
|
84
|
+
it('adds upstream labels without removing local-only ones', () => {
|
|
85
|
+
expect(unionLabels(['inspect', 'agents'], ['bug', 'help wanted']))
|
|
86
|
+
.toEqual(['inspect', 'agents', 'bug', 'help wanted']);
|
|
87
|
+
});
|
|
88
|
+
it('does not duplicate labels present on both sides', () => {
|
|
89
|
+
expect(unionLabels(['bug', 'ui'], ['bug'])).toEqual(['bug', 'ui']);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
describe('closedReasonFrom', () => {
|
|
93
|
+
it('normalises GitHub casing and spacing', () => {
|
|
94
|
+
expect(closedReasonFrom('NOT_PLANNED')).toBe('not_planned');
|
|
95
|
+
expect(closedReasonFrom('not planned')).toBe('not_planned');
|
|
96
|
+
expect(closedReasonFrom('DUPLICATE')).toBe('duplicate');
|
|
97
|
+
});
|
|
98
|
+
it('falls back to completed for anything else', () => {
|
|
99
|
+
expect(closedReasonFrom(null)).toBe('completed');
|
|
100
|
+
expect(closedReasonFrom('REOPENED')).toBe('completed');
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
describe('comment markers', () => {
|
|
104
|
+
it('round-trips an id through a comment body', () => {
|
|
105
|
+
const marked = markComment('IC_123', 'Reproduced on Firefox too.');
|
|
106
|
+
expect(commentGithubId(marked)).toBe('IC_123');
|
|
107
|
+
expect(stripCommentMarker(marked)).toBe('Reproduced on Firefox too.');
|
|
108
|
+
});
|
|
109
|
+
it('reports no id for a locally-authored comment', () => {
|
|
110
|
+
expect(commentGithubId('Just a local note.')).toBeNull();
|
|
111
|
+
});
|
|
112
|
+
it('survives a body that itself starts with an HTML comment', () => {
|
|
113
|
+
const marked = markComment('IC_9', '<!-- not a marker -->\nText');
|
|
114
|
+
expect(commentGithubId(marked)).toBe('IC_9');
|
|
115
|
+
expect(stripCommentMarker(marked)).toBe('<!-- not a marker -->\nText');
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
//# sourceMappingURL=gh-issues.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gh-issues.test.js","sourceRoot":"","sources":["../../src/github/gh-issues.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The GitHub actions on the `issues` tool.
|
|
3
|
+
*
|
|
4
|
+
* Only `publish` and `sync` touch the network; `link` never does. Everything
|
|
5
|
+
* here is written so that failing offline costs nothing: reads happen first,
|
|
6
|
+
* local writes second, upstream writes last, and any gh failure aborts before
|
|
7
|
+
* the first local mutation.
|
|
8
|
+
*/
|
|
9
|
+
import { type RunGhOptions } from './gh-cli.js';
|
|
10
|
+
import { type IssueType } from '../issue-tracker.js';
|
|
11
|
+
export interface GithubActionArgs {
|
|
12
|
+
id?: number;
|
|
13
|
+
github?: number;
|
|
14
|
+
repo?: string;
|
|
15
|
+
confirm?: boolean;
|
|
16
|
+
take?: 'local' | 'remote';
|
|
17
|
+
fromComment?: number;
|
|
18
|
+
allowPrivilegedSteps?: boolean;
|
|
19
|
+
type?: IssueType;
|
|
20
|
+
}
|
|
21
|
+
export interface GithubActionDeps {
|
|
22
|
+
/** Injected so tests never spawn gh. Defaults to the real module. */
|
|
23
|
+
runOpts?: RunGhOptions;
|
|
24
|
+
}
|
|
25
|
+
/** Every handler funnels gh failures through here, so one taxonomy covers all. */
|
|
26
|
+
export declare function ghErrorResponse(err: unknown): any;
|
|
27
|
+
export declare function handlePublish(args: GithubActionArgs, deps?: GithubActionDeps): Promise<any>;
|
|
28
|
+
export declare function handleLink(args: GithubActionArgs): Promise<any>;
|
|
29
|
+
export declare function handleImport(args: GithubActionArgs, deps?: GithubActionDeps): Promise<any>;
|
|
30
|
+
export declare function handleSync(args: GithubActionArgs, deps?: GithubActionDeps): Promise<any>;
|
|
31
|
+
export declare function handlePullSequence(args: GithubActionArgs, deps?: GithubActionDeps & {
|
|
32
|
+
knownTools?: () => string[];
|
|
33
|
+
}): Promise<any>;
|
|
34
|
+
//# sourceMappingURL=issue-actions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"issue-actions.d.ts","sourceRoot":"","sources":["../../src/github/issue-actions.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAYnE,OAAO,EAKc,KAAK,SAAS,EAClC,MAAM,qBAAqB,CAAC;AAM7B,MAAM,WAAW,gBAAgB;IAC/B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,qEAAqE;IACrE,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB;AAED,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,CAoBjD;AAsED,wBAAsB,aAAa,CAAC,IAAI,EAAE,gBAAgB,EAAE,IAAI,GAAE,gBAAqB,GAAG,OAAO,CAAC,GAAG,CAAC,CAiGrG;AAMD,wBAAsB,UAAU,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,GAAG,CAAC,CAiBrE;AAUD,wBAAsB,YAAY,CAAC,IAAI,EAAE,gBAAgB,EAAE,IAAI,GAAE,gBAAqB,GAAG,OAAO,CAAC,GAAG,CAAC,CAuDpG;AA6GD,wBAAsB,UAAU,CAAC,IAAI,EAAE,gBAAgB,EAAE,IAAI,GAAE,gBAAqB,GAAG,OAAO,CAAC,GAAG,CAAC,CAiGlG;AAMD,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,gBAAgB,EACtB,IAAI,GAAE,gBAAgB,GAAG;IAAE,UAAU,CAAC,EAAE,MAAM,MAAM,EAAE,CAAA;CAAO,GAC5D,OAAO,CAAC,GAAG,CAAC,CAoGd"}
|