acdev 1.0.16 → 1.1.1
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/package.json +1 -1
- package/public/app.js +29 -0
- package/public/index.html +16 -0
- package/public/styles.css +7 -0
- package/src/agent.js +12 -0
- package/src/server.js +16 -0
- package/src/store.js +11 -8
package/package.json
CHANGED
package/public/app.js
CHANGED
|
@@ -240,6 +240,7 @@ const els = {
|
|
|
240
240
|
overviewTicketSource: document.getElementById('overview-ticket-source'),
|
|
241
241
|
enqueueFeedback: document.getElementById('enqueue-feedback'),
|
|
242
242
|
preferredBranch: document.getElementById('preferred-branch'),
|
|
243
|
+
enqueueUserPrompt: document.getElementById('enqueue-user-prompt'),
|
|
243
244
|
addBtn: document.getElementById('add-btn'),
|
|
244
245
|
statsGrid: document.getElementById('stats-grid'),
|
|
245
246
|
overviewRunning: document.getElementById('overview-running'),
|
|
@@ -301,6 +302,8 @@ const els = {
|
|
|
301
302
|
settingsModelValue: document.getElementById('settings-model-value'),
|
|
302
303
|
settingsModelPanel: document.getElementById('settings-model-panel'),
|
|
303
304
|
settingsModelList: document.getElementById('settings-model-list'),
|
|
305
|
+
settingsModelSearch: document.getElementById('settings-model-search'),
|
|
306
|
+
settingsModelHint: document.getElementById('settings-model-hint'),
|
|
304
307
|
reviewPrLink: document.getElementById('review-pr-link'),
|
|
305
308
|
reviewPrStatusLine: document.getElementById('review-pr-status-line'),
|
|
306
309
|
reviewPrStatusNotes: document.getElementById('review-pr-status-notes'),
|
|
@@ -308,6 +311,10 @@ const els = {
|
|
|
308
311
|
reviewTerminalMessage: document.getElementById('review-terminal-message'),
|
|
309
312
|
reviewRetryBtn: document.getElementById('review-retry-btn'),
|
|
310
313
|
settingsTools: document.getElementById('settings-tools'),
|
|
314
|
+
settingsMaxTurns: document.getElementById('settings-max-turns'),
|
|
315
|
+
settingsTimeout: document.getElementById('settings-timeout'),
|
|
316
|
+
settingsTimeoutMs: document.getElementById('settings-timeout-ms'),
|
|
317
|
+
settingsTestCommand: document.getElementById('settings-test-command'),
|
|
311
318
|
settingsFeedback: document.getElementById('settings-feedback'),
|
|
312
319
|
settingsSaveBtn: document.getElementById('settings-save-btn'),
|
|
313
320
|
settingsTicketSource: document.getElementById('settings-ticket-source'),
|
|
@@ -1572,6 +1579,24 @@ function formatLogEvent(event) {
|
|
|
1572
1579
|
};
|
|
1573
1580
|
}
|
|
1574
1581
|
|
|
1582
|
+
if (event.type === 'warn') {
|
|
1583
|
+
return {
|
|
1584
|
+
kind: 'warn',
|
|
1585
|
+
label: 'Warning',
|
|
1586
|
+
text: String(event.payload || 'Warning'),
|
|
1587
|
+
raw,
|
|
1588
|
+
};
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
if (event.type === 'info') {
|
|
1592
|
+
return {
|
|
1593
|
+
kind: 'status',
|
|
1594
|
+
label: 'Info',
|
|
1595
|
+
text: String(event.payload || ''),
|
|
1596
|
+
raw,
|
|
1597
|
+
};
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1575
1600
|
if (event.type === 'agent_event') {
|
|
1576
1601
|
const msg = event.payload;
|
|
1577
1602
|
if (msg && typeof msg === 'object') {
|
|
@@ -2842,6 +2867,7 @@ function renderReview(jobs) {
|
|
|
2842
2867
|
if (els.reviewPrStatusNotes) els.reviewPrStatusNotes.innerHTML = '';
|
|
2843
2868
|
}
|
|
2844
2869
|
els.reviewTerminalSection.classList.toggle('hidden', !isTerminal);
|
|
2870
|
+
const prMeta = resolvePrMeta(job);
|
|
2845
2871
|
if (document.activeElement !== els.prTitle && document.activeElement !== els.prBody) {
|
|
2846
2872
|
els.prTitle.value = prMeta.prTitle;
|
|
2847
2873
|
els.prBody.value = prMeta.prBody;
|
|
@@ -5143,6 +5169,7 @@ els.addBtn.addEventListener('click', async () => {
|
|
|
5143
5169
|
|
|
5144
5170
|
const urls = splitIssueUrls(text);
|
|
5145
5171
|
const branchName = els.preferredBranch?.value?.trim() || '';
|
|
5172
|
+
const userPrompt = els.enqueueUserPrompt?.value?.trim() || '';
|
|
5146
5173
|
|
|
5147
5174
|
try {
|
|
5148
5175
|
const res = await fetch('/api/issues', {
|
|
@@ -5152,6 +5179,7 @@ els.addBtn.addEventListener('click', async () => {
|
|
|
5152
5179
|
urls,
|
|
5153
5180
|
ticketSource,
|
|
5154
5181
|
...(branchName ? { branchName } : {}),
|
|
5182
|
+
...(userPrompt ? { userPrompt } : {}),
|
|
5155
5183
|
}),
|
|
5156
5184
|
});
|
|
5157
5185
|
const data = await res.json();
|
|
@@ -5164,6 +5192,7 @@ els.addBtn.addEventListener('click', async () => {
|
|
|
5164
5192
|
}
|
|
5165
5193
|
els.issueUrls.value = '';
|
|
5166
5194
|
if (els.preferredBranch) els.preferredBranch.value = '';
|
|
5195
|
+
if (els.enqueueUserPrompt) els.enqueueUserPrompt.value = '';
|
|
5167
5196
|
const parts = [];
|
|
5168
5197
|
if (data.jobs?.length) parts.push(`Added ${data.jobs.length}`);
|
|
5169
5198
|
if (data.skipped?.length) {
|
package/public/index.html
CHANGED
|
@@ -156,6 +156,22 @@
|
|
|
156
156
|
</p>
|
|
157
157
|
</div>
|
|
158
158
|
|
|
159
|
+
<div class="enqueue-branch-field">
|
|
160
|
+
<div class="enqueue-branch-label-row">
|
|
161
|
+
<label class="field-label" for="enqueue-user-prompt">Additional instructions</label>
|
|
162
|
+
<span class="enqueue-branch-optional">Optional</span>
|
|
163
|
+
</div>
|
|
164
|
+
<textarea
|
|
165
|
+
id="enqueue-user-prompt"
|
|
166
|
+
class="input textarea enqueue-textarea"
|
|
167
|
+
rows="3"
|
|
168
|
+
placeholder="Anything specific you want the agent to know or do…"
|
|
169
|
+
></textarea>
|
|
170
|
+
<p class="enqueue-input-hint">
|
|
171
|
+
Appended to the agent's instructions for these tickets. Leave empty to use the issue content only.
|
|
172
|
+
</p>
|
|
173
|
+
</div>
|
|
174
|
+
|
|
159
175
|
<div class="enqueue-info-banner" id="enqueue-info-banner" role="note">
|
|
160
176
|
<svg class="enqueue-info-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
161
177
|
<circle cx="12" cy="12" r="10"/>
|
package/public/styles.css
CHANGED
|
@@ -1444,6 +1444,13 @@ a { color: var(--primary); text-underline-offset: 3px; }
|
|
|
1444
1444
|
.log-line.is-error .log-kind,
|
|
1445
1445
|
.log-line.is-error .log-msg { color: var(--accent-800); }
|
|
1446
1446
|
|
|
1447
|
+
.log-line.is-warn {
|
|
1448
|
+
border-left-color: var(--amber);
|
|
1449
|
+
background: var(--amber-100);
|
|
1450
|
+
}
|
|
1451
|
+
.log-line.is-warn .log-kind,
|
|
1452
|
+
.log-line.is-warn .log-msg { color: var(--amber-800); }
|
|
1453
|
+
|
|
1447
1454
|
.log-raw { margin-top: 4px; }
|
|
1448
1455
|
|
|
1449
1456
|
.log-raw > summary {
|
package/src/agent.js
CHANGED
|
@@ -89,6 +89,7 @@ export function stripAiAttribution(text) {
|
|
|
89
89
|
* comments?: Array<{ author: string, body: string }>,
|
|
90
90
|
* },
|
|
91
91
|
* jiraPrLinkPhrase?: string,
|
|
92
|
+
* userPrompt?: string,
|
|
92
93
|
* }} [context]
|
|
93
94
|
*/
|
|
94
95
|
export function buildPrompt(issueUrl, config, context = {}) {
|
|
@@ -163,6 +164,14 @@ export function buildPrompt(issueUrl, config, context = {}) {
|
|
|
163
164
|
);
|
|
164
165
|
}
|
|
165
166
|
|
|
167
|
+
if (context.userPrompt && context.userPrompt.trim()) {
|
|
168
|
+
parts.push(
|
|
169
|
+
'',
|
|
170
|
+
'Additional instructions from the user (optional — follow them unless they conflict with the rules above):',
|
|
171
|
+
context.userPrompt.trim()
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
166
175
|
// Drop empty strings from optional browse URL line
|
|
167
176
|
const cleaned = parts.filter((p) => p !== '');
|
|
168
177
|
|
|
@@ -579,6 +588,7 @@ function stubAgentResult(onEvent, title, body) {
|
|
|
579
588
|
* ticketSource?: 'github' | 'jira',
|
|
580
589
|
* jiraKey?: string,
|
|
581
590
|
* jiraIssue?: object,
|
|
591
|
+
* userPrompt?: string,
|
|
582
592
|
* queryFn?: typeof query,
|
|
583
593
|
* callModelFn?: (args: object) => object,
|
|
584
594
|
* }} params
|
|
@@ -594,6 +604,7 @@ export async function runAgentOnIssue({
|
|
|
594
604
|
ticketSource,
|
|
595
605
|
jiraKey,
|
|
596
606
|
jiraIssue,
|
|
607
|
+
userPrompt,
|
|
597
608
|
queryFn = query,
|
|
598
609
|
callModelFn,
|
|
599
610
|
}) {
|
|
@@ -613,6 +624,7 @@ export async function runAgentOnIssue({
|
|
|
613
624
|
jiraKey,
|
|
614
625
|
jiraIssue,
|
|
615
626
|
jiraPrLinkPhrase: config.jiraPrLinkPhrase,
|
|
627
|
+
userPrompt,
|
|
616
628
|
});
|
|
617
629
|
|
|
618
630
|
const { resultText, meta, usage } = await runConfiguredQuery({
|
package/src/server.js
CHANGED
|
@@ -68,6 +68,9 @@ const CLEARABLE_STATUSES = new Set([
|
|
|
68
68
|
'failed',
|
|
69
69
|
]);
|
|
70
70
|
|
|
71
|
+
/** Max length for optional user-supplied prompt appended to the agent instructions. */
|
|
72
|
+
const USER_PROMPT_MAX_LEN = 4000;
|
|
73
|
+
|
|
71
74
|
/**
|
|
72
75
|
* Worktree directory id: Jira key or GitHub issue number.
|
|
73
76
|
* @param {{ jiraKey?: string, issueNumber?: number }} job
|
|
@@ -471,6 +474,7 @@ export function createServer({ repoRoot, config, store, useStubAgent = false, de
|
|
|
471
474
|
ticketSource: isJira ? 'jira' : 'github',
|
|
472
475
|
jiraKey: job.jiraKey,
|
|
473
476
|
jiraIssue,
|
|
477
|
+
userPrompt: job.userPrompt,
|
|
474
478
|
});
|
|
475
479
|
|
|
476
480
|
if (!store.getJob(jobId)) return;
|
|
@@ -833,6 +837,17 @@ export function createServer({ repoRoot, config, store, useStubAgent = false, de
|
|
|
833
837
|
}
|
|
834
838
|
const preferredBranchName = preferredParsed.value;
|
|
835
839
|
|
|
840
|
+
const rawUserPrompt = req.body?.userPrompt;
|
|
841
|
+
if (rawUserPrompt != null && typeof rawUserPrompt !== 'string') {
|
|
842
|
+
return res.status(400).json({ error: 'userPrompt must be a string' });
|
|
843
|
+
}
|
|
844
|
+
const userPrompt = typeof rawUserPrompt === 'string' ? rawUserPrompt.trim() : '';
|
|
845
|
+
if (userPrompt.length > USER_PROMPT_MAX_LEN) {
|
|
846
|
+
return res.status(400).json({
|
|
847
|
+
error: `userPrompt must be ${USER_PROMPT_MAX_LEN} characters or fewer.`,
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
|
|
836
851
|
const ticketSource =
|
|
837
852
|
req.body?.ticketSource === 'jira' || req.body?.ticketSource === 'github'
|
|
838
853
|
? req.body.ticketSource
|
|
@@ -929,6 +944,7 @@ export function createServer({ repoRoot, config, store, useStubAgent = false, de
|
|
|
929
944
|
ticketSource: item.ticketSource,
|
|
930
945
|
jiraKey: item.jiraKey,
|
|
931
946
|
...(preferredBranchName ? { preferredBranchName } : {}),
|
|
947
|
+
...(userPrompt ? { userPrompt } : {}),
|
|
932
948
|
llmProvider: llm.llmProvider,
|
|
933
949
|
model: llm.model,
|
|
934
950
|
});
|
package/src/store.js
CHANGED
|
@@ -53,19 +53,21 @@ export class Store {
|
|
|
53
53
|
* @param {{
|
|
54
54
|
* issueUrl: string,
|
|
55
55
|
* issueNumber?: number,
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
56
|
+
* ticketSource?: 'github' | 'jira',
|
|
57
|
+
* jiraKey?: string,
|
|
58
|
+
* preferredBranchName?: string,
|
|
59
|
+
* llmProvider?: 'claude' | 'openrouter',
|
|
60
|
+
* model?: string,
|
|
61
|
+
* userPrompt?: string,
|
|
62
|
+
* }} data
|
|
63
|
+
* @returns {Job}
|
|
64
|
+
*/
|
|
64
65
|
addJob(data) {
|
|
65
66
|
const now = new Date().toISOString();
|
|
66
67
|
const ticketSource = data.ticketSource === 'jira' ? 'jira' : 'github';
|
|
67
68
|
const llmProvider = data.llmProvider === 'openrouter' ? 'openrouter' : 'claude';
|
|
68
69
|
const model = typeof data.model === 'string' ? data.model.trim() : '';
|
|
70
|
+
const userPrompt = typeof data.userPrompt === 'string' ? data.userPrompt.trim() : '';
|
|
69
71
|
/** @type {Job} */
|
|
70
72
|
const job = {
|
|
71
73
|
id: randomUUID(),
|
|
@@ -76,6 +78,7 @@ export class Store {
|
|
|
76
78
|
...(model ? { model } : {}),
|
|
77
79
|
...(data.jiraKey ? { jiraKey: data.jiraKey } : {}),
|
|
78
80
|
...(data.preferredBranchName ? { preferredBranchName: data.preferredBranchName } : {}),
|
|
81
|
+
...(userPrompt ? { userPrompt } : {}),
|
|
79
82
|
status: 'queued',
|
|
80
83
|
createdAt: now,
|
|
81
84
|
updatedAt: now,
|