@todoist/doistbot-cli 0.0.0-stage → 1.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/auth.js +225 -0
- package/dist/actions/doctor.js +39 -0
- package/dist/actions/review-usage.js +25 -0
- package/dist/actions/review.js +311 -0
- package/dist/actions/setup.js +14 -0
- package/dist/auth.js +202 -0
- package/dist/config.js +145 -0
- package/dist/env.js +10 -0
- package/dist/file-store.js +112 -0
- package/dist/index.js +164 -0
- package/dist/input.js +40 -0
- package/dist/runtime.js +105 -0
- package/dist/secure-store.js +148 -0
- package/dist/terminal.js +185 -0
- package/dist/test-utils/secure-store-mocks.js +29 -0
- package/dist/update-cache-entrypoint.js +16 -0
- package/dist/update-check.js +235 -0
- package/package.json +65 -5
- package/sandbox/_node_modules/doistbot-logging/dist/index.d.ts +23 -0
- package/sandbox/_node_modules/doistbot-logging/dist/index.js +51 -0
- package/sandbox/_node_modules/doistbot-logging/package.json +12 -0
- package/sandbox/_node_modules/doistbot-repo-config/dist/index.d.ts +93 -0
- package/sandbox/_node_modules/doistbot-repo-config/dist/index.js +197 -0
- package/sandbox/_node_modules/doistbot-repo-config/package.json +12 -0
- package/sandbox/dist/core/autofix-resources.js +58 -0
- package/sandbox/dist/core/autofix-service-query.js +69 -0
- package/sandbox/dist/core/autofix-test-policy.js +11 -0
- package/sandbox/dist/core/autofix-verification.js +355 -0
- package/sandbox/dist/core/bot-logins.js +14 -0
- package/sandbox/dist/core/check-run.js +158 -0
- package/sandbox/dist/core/datadog-metrics.js +113 -0
- package/sandbox/dist/core/environment.js +49 -0
- package/sandbox/dist/core/git-auth.js +17 -0
- package/sandbox/dist/core/github-history.js +4 -0
- package/sandbox/dist/core/github-issues.js +18 -0
- package/sandbox/dist/core/label-parsing.js +1 -0
- package/sandbox/dist/core/langfuse-observation.js +33 -0
- package/sandbox/dist/core/langfuse-session.js +39 -0
- package/sandbox/dist/core/logger-span-processor.js +90 -0
- package/sandbox/dist/core/logging.js +18 -0
- package/sandbox/dist/core/pi-autofix-extension.js +188 -0
- package/sandbox/dist/core/pi-execution-limits-extension.js +79 -0
- package/sandbox/dist/core/pi-progress-logging.js +51 -0
- package/sandbox/dist/core/pi-tool-output-filter-extension.js +65 -0
- package/sandbox/dist/core/pi.js +870 -0
- package/sandbox/dist/core/pii-scrubber.js +31 -0
- package/sandbox/dist/core/prompt-template.js +63 -0
- package/sandbox/dist/core/reactions.js +36 -0
- package/sandbox/dist/core/regexp.js +3 -0
- package/sandbox/dist/core/repository-map.js +1 -0
- package/sandbox/dist/core/repository-resolver.js +1 -0
- package/sandbox/dist/core/retry.js +29 -0
- package/sandbox/dist/core/s3-utils.js +42 -0
- package/sandbox/dist/core/shared.js +124 -0
- package/sandbox/dist/core/snapshot-helpers.js +17 -0
- package/sandbox/dist/core/span-test-helpers.js +13 -0
- package/sandbox/dist/core/tool-environment.js +83 -0
- package/sandbox/dist/core/tool-output.js +18 -0
- package/sandbox/dist/core/tracing-setup.js +92 -0
- package/sandbox/dist/core/tracing.js +81 -0
- package/sandbox/dist/main.js +51 -0
- package/sandbox/dist/providers/config.js +23 -0
- package/sandbox/dist/providers/credentials.js +40 -0
- package/sandbox/dist/providers/gemini.js +28 -0
- package/sandbox/dist/providers/helpers.js +253 -0
- package/sandbox/dist/providers/index.js +27 -0
- package/sandbox/dist/providers/openai.js +23 -0
- package/sandbox/dist/providers/openrouter-pi.js +25 -0
- package/sandbox/dist/providers/pi-review.js +301 -0
- package/sandbox/dist/providers/process.js +34 -0
- package/sandbox/dist/providers/schemas.js +61 -0
- package/sandbox/dist/providers/types.js +4 -0
- package/sandbox/dist/tasks/chat/chat.js +440 -0
- package/sandbox/dist/tasks/chat/prompt.js +20 -0
- package/sandbox/dist/tasks/issue-fix-retry/fix-retry.js +304 -0
- package/sandbox/dist/tasks/issue-summarize/context.js +21 -0
- package/sandbox/dist/tasks/issue-summarize/media.js +335 -0
- package/sandbox/dist/tasks/issue-summarize/model.js +230 -0
- package/sandbox/dist/tasks/issue-summarize/output.js +45 -0
- package/sandbox/dist/tasks/issue-summarize/prompt.js +11 -0
- package/sandbox/dist/tasks/issue-summarize/summarize.js +238 -0
- package/sandbox/dist/tasks/issue-summarize/thread.js +123 -0
- package/sandbox/dist/tasks/issue-summarize/types.js +1 -0
- package/sandbox/dist/tasks/issue-triage/assignee-review.js +114 -0
- package/sandbox/dist/tasks/issue-triage/autofix-capabilities.js +22 -0
- package/sandbox/dist/tasks/issue-triage/autofix-checkpoint.js +122 -0
- package/sandbox/dist/tasks/issue-triage/autofix-policy.js +36 -0
- package/sandbox/dist/tasks/issue-triage/clone.js +40 -0
- package/sandbox/dist/tasks/issue-triage/context.js +57 -0
- package/sandbox/dist/tasks/issue-triage/diff-validator.js +102 -0
- package/sandbox/dist/tasks/issue-triage/fix-attempt.js +617 -0
- package/sandbox/dist/tasks/issue-triage/fix-context.js +5 -0
- package/sandbox/dist/tasks/issue-triage/fix-dispatch.js +263 -0
- package/sandbox/dist/tasks/issue-triage/fix-failure-reasons.js +2 -0
- package/sandbox/dist/tasks/issue-triage/fix-loop/effects.js +526 -0
- package/sandbox/dist/tasks/issue-triage/fix-loop/effects.types.js +1 -0
- package/sandbox/dist/tasks/issue-triage/fix-loop/fake-effects.js +65 -0
- package/sandbox/dist/tasks/issue-triage/fix-loop/promotion-task.js +108 -0
- package/sandbox/dist/tasks/issue-triage/fix-loop/recovery.js +512 -0
- package/sandbox/dist/tasks/issue-triage/fix-loop/runners.js +233 -0
- package/sandbox/dist/tasks/issue-triage/fix-loop/state-machine.js +171 -0
- package/sandbox/dist/tasks/issue-triage/github-request.js +2 -0
- package/sandbox/dist/tasks/issue-triage/hero-group-map.js +206 -0
- package/sandbox/dist/tasks/issue-triage/markers.js +6 -0
- package/sandbox/dist/tasks/issue-triage/model.js +124 -0
- package/sandbox/dist/tasks/issue-triage/output.js +164 -0
- package/sandbox/dist/tasks/issue-triage/pr-creator.js +585 -0
- package/sandbox/dist/tasks/issue-triage/pr-readiness.js +25 -0
- package/sandbox/dist/tasks/issue-triage/prompt.js +63 -0
- package/sandbox/dist/tasks/issue-triage/repo-config.js +47 -0
- package/sandbox/dist/tasks/issue-triage/repo-prompts.js +77 -0
- package/sandbox/dist/tasks/issue-triage/report-fixture.js +53 -0
- package/sandbox/dist/tasks/issue-triage/report-history.js +113 -0
- package/sandbox/dist/tasks/issue-triage/report-schema.js +63 -0
- package/sandbox/dist/tasks/issue-triage/report.js +111 -0
- package/sandbox/dist/tasks/issue-triage/resolution.js +30 -0
- package/sandbox/dist/tasks/issue-triage/routing.js +169 -0
- package/sandbox/dist/tasks/issue-triage/sandbox-environment.js +59 -0
- package/sandbox/dist/tasks/issue-triage/shared.js +86 -0
- package/sandbox/dist/tasks/issue-triage/side-effects.js +102 -0
- package/sandbox/dist/tasks/issue-triage/triage.js +442 -0
- package/sandbox/dist/tasks/issue-triage/types.js +1 -0
- package/sandbox/dist/tasks/persist-logs/context.js +19 -0
- package/sandbox/dist/tasks/persist-logs/dd-proxy.js +116 -0
- package/sandbox/dist/tasks/persist-logs/llm-query-planner.js +156 -0
- package/sandbox/dist/tasks/persist-logs/persist-logs.js +491 -0
- package/sandbox/dist/tasks/refresh-s3-urls/refresh-s3-urls.js +214 -0
- package/sandbox/dist/tasks/review/check-run.js +326 -0
- package/sandbox/dist/tasks/review/comment-mapper.js +46 -0
- package/sandbox/dist/tasks/review/conversation-context.js +477 -0
- package/sandbox/dist/tasks/review/diff.js +95 -0
- package/sandbox/dist/tasks/review/engines/dedupe.js +291 -0
- package/sandbox/dist/tasks/review/engines/multi-focus.js +419 -0
- package/sandbox/dist/tasks/review/engines/shared.js +87 -0
- package/sandbox/dist/tasks/review/engines/types.js +1 -0
- package/sandbox/dist/tasks/review/finding-output.js +18 -0
- package/sandbox/dist/tasks/review/format.js +17 -0
- package/sandbox/dist/tasks/review/github-comment-format.js +94 -0
- package/sandbox/dist/tasks/review/local-git.js +374 -0
- package/sandbox/dist/tasks/review/local.js +118 -0
- package/sandbox/dist/tasks/review/multi-focus-prompt.js +59 -0
- package/sandbox/dist/tasks/review/prompt.js +81 -0
- package/sandbox/dist/tasks/review/review-feedback.js +48 -0
- package/sandbox/dist/tasks/review/review-mode-github.js +58 -0
- package/sandbox/dist/tasks/review/review-mode-policy.js +232 -0
- package/sandbox/dist/tasks/review/review-mode-types.js +1 -0
- package/sandbox/dist/tasks/review/review-mode.js +296 -0
- package/sandbox/dist/tasks/review/review-summary.js +123 -0
- package/sandbox/dist/tasks/review/review.js +391 -0
- package/sandbox/dist/tasks/review/runner.js +255 -0
- package/sandbox/dist/tasks/review/severity.js +5 -0
- package/sandbox/dist/tasks/review/summary-model.js +271 -0
- package/sandbox/dist/tasks/review/thinking-level.js +14 -0
- package/sandbox/dist/tasks/review/translation-review-policy.js +37 -0
- package/sandbox/dist/tasks/review/types.js +1 -0
- package/sandbox/dist/tasks/review-slice-plan/context.js +66 -0
- package/sandbox/dist/tasks/review-slice-plan/plan.js +210 -0
- package/sandbox/dist/tasks/review-slice-plan/prompt.js +59 -0
- package/sandbox/dist/tasks/review-slice-plan/review-slice-plan.js +367 -0
- package/sandbox/dist/tasks/sentry-triage/store.js +133 -0
- package/sandbox/dist/tasks/sentry-triage/triage.js +217 -0
- package/sandbox/node_modules/doistbot-logging/dist/index.d.ts +23 -0
- package/sandbox/node_modules/doistbot-logging/dist/index.js +51 -0
- package/sandbox/node_modules/doistbot-logging/package.json +12 -0
- package/sandbox/node_modules/doistbot-repo-config/dist/index.d.ts +93 -0
- package/sandbox/node_modules/doistbot-repo-config/dist/index.js +197 -0
- package/sandbox/node_modules/doistbot-repo-config/package.json +12 -0
- package/sandbox/src/review/prompts/ai-internal-tools.md +254 -0
- package/sandbox/src/review/prompts/backend-repository-standards.md +102 -0
- package/sandbox/src/review/prompts/observability-standard.md +169 -0
- package/sandbox/src/review/prompts/outline-map.json +26 -0
- package/sandbox/src/review/prompts/secrets-management.md +286 -0
- package/sandbox/src/review/prompts/service-production-readiness.md +122 -0
- package/sandbox/src/review/prompts/workload-placement.md +345 -0
- package/sandbox/src/tasks/review/prompts/review-focus-prompts/efficiency.md +16 -0
- package/sandbox/src/tasks/review/prompts/review-focus-prompts/general.md +32 -0
- package/sandbox/src/tasks/review/prompts/review-focus-prompts/quality.md +20 -0
- package/sandbox/src/tasks/review/prompts/review-focus-prompts/reuse.md +13 -0
- package/sandbox/src/tasks/review/prompts/review-focus-prompts/security.md +18 -0
- package/sandbox/src/tasks/review/prompts/review-focus-prompts/standards.md +21 -0
- package/sandbox/src/tasks/review/prompts/review-focus-prompts/tests.md +19 -0
- package/sandbox/src/tasks/review/prompts/review-mode.md +40 -0
- package/sandbox/src/tasks/review/prompts/review-multi-focus-base-prompt.md +142 -0
- package/scripts/restore-runtime-assets.mjs +21 -0
- package/README.md +0 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { optionalPositiveInt, requiredEnv, requiredPositiveInt } from '../../core/environment.js';
|
|
2
|
+
export function parsePersistLogsContext(env = process.env) {
|
|
3
|
+
return {
|
|
4
|
+
owner: requiredEnv('REPO_OWNER', env),
|
|
5
|
+
repo: requiredEnv('REPO_NAME', env),
|
|
6
|
+
issueNumber: requiredPositiveInt('ISSUE_NUMBER', env),
|
|
7
|
+
installationId: requiredPositiveInt('INSTALLATION_ID', env),
|
|
8
|
+
appId: requiredEnv('APP_ID', env),
|
|
9
|
+
privateKey: requiredEnv('PRIVATE_KEY', env),
|
|
10
|
+
datadogApiKey: requiredEnv('DATADOG_API_KEY', env),
|
|
11
|
+
datadogAppKey: requiredEnv('DATADOG_APP_KEY', env),
|
|
12
|
+
openaiApiKey: requiredEnv('OPENAI_KEY', env),
|
|
13
|
+
logSnapshotBucket: env.LOG_SNAPSHOT_BUCKET?.trim() || '',
|
|
14
|
+
dryRun: env.DRY_RUN?.toLowerCase() === 'true',
|
|
15
|
+
commentId: optionalPositiveInt(env.COMMENT_ID),
|
|
16
|
+
reactionId: optionalPositiveInt(env.REACTION_ID),
|
|
17
|
+
deliveryId: env.DELIVERY_ID?.trim() || 'unknown',
|
|
18
|
+
};
|
|
19
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import http from 'http';
|
|
2
|
+
import https from 'https';
|
|
3
|
+
import { logger } from '../../core/logging.js';
|
|
4
|
+
import { scrubPii, scrubPiiFromObject } from '../../core/pii-scrubber.js';
|
|
5
|
+
const DD_HOST = 'api.datadoghq.com';
|
|
6
|
+
/**
|
|
7
|
+
* Starts a localhost HTTP proxy that forwards requests to the Datadog API,
|
|
8
|
+
* scrubs PII from responses, and logs each query for auditability.
|
|
9
|
+
*
|
|
10
|
+
* The agent hits http://localhost:{port}/api/v2/... instead of the DD API directly.
|
|
11
|
+
* The proxy injects DD auth headers so the agent never sees the API keys.
|
|
12
|
+
*/
|
|
13
|
+
export function startDdProxy({ port, datadogApiKey, datadogAppKey }) {
|
|
14
|
+
return new Promise((resolve, reject) => {
|
|
15
|
+
const server = http.createServer((req, res) => {
|
|
16
|
+
const body = [];
|
|
17
|
+
req.on('data', (chunk) => body.push(chunk));
|
|
18
|
+
req.on('end', () => {
|
|
19
|
+
const requestBody = Buffer.concat(body).toString();
|
|
20
|
+
const urlPath = req.url ?? '/';
|
|
21
|
+
// Log the query for audit trail (queries contain no PII)
|
|
22
|
+
let queryString = '';
|
|
23
|
+
try {
|
|
24
|
+
const parsed = JSON.parse(requestBody);
|
|
25
|
+
queryString = parsed?.filter?.query ?? '';
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
// Not JSON or no query field — that's fine
|
|
29
|
+
}
|
|
30
|
+
logger.info('DD proxy: forwarding query', {
|
|
31
|
+
task: 'persist-logs',
|
|
32
|
+
path: urlPath,
|
|
33
|
+
method: req.method,
|
|
34
|
+
query: scrubPii(queryString),
|
|
35
|
+
});
|
|
36
|
+
const options = {
|
|
37
|
+
hostname: DD_HOST,
|
|
38
|
+
port: 443,
|
|
39
|
+
path: urlPath,
|
|
40
|
+
method: req.method ?? 'GET',
|
|
41
|
+
headers: {
|
|
42
|
+
'Content-Type': 'application/json',
|
|
43
|
+
'DD-API-KEY': datadogApiKey,
|
|
44
|
+
'DD-APPLICATION-KEY': datadogAppKey,
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
const proxyReq = https.request(options, (proxyRes) => {
|
|
48
|
+
const chunks = [];
|
|
49
|
+
proxyRes.on('error', (err) => {
|
|
50
|
+
logger.error('DD proxy: upstream response error', {
|
|
51
|
+
task: 'persist-logs',
|
|
52
|
+
error: err.message,
|
|
53
|
+
path: urlPath,
|
|
54
|
+
});
|
|
55
|
+
if (!res.headersSent) {
|
|
56
|
+
res.writeHead(502);
|
|
57
|
+
res.end(JSON.stringify({ error: 'DD proxy upstream response error' }));
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
proxyRes.on('data', (chunk) => chunks.push(chunk));
|
|
61
|
+
proxyRes.on('end', () => {
|
|
62
|
+
const rawResponse = Buffer.concat(chunks).toString();
|
|
63
|
+
let scrubbedResponse;
|
|
64
|
+
try {
|
|
65
|
+
const parsed = JSON.parse(rawResponse);
|
|
66
|
+
const scrubbed = scrubPiiFromObject(parsed);
|
|
67
|
+
scrubbedResponse = JSON.stringify(scrubbed);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
// Non-JSON response — scrub as plain text
|
|
71
|
+
scrubbedResponse = scrubPii(rawResponse);
|
|
72
|
+
}
|
|
73
|
+
logger.info('DD proxy: response scrubbed', {
|
|
74
|
+
task: 'persist-logs',
|
|
75
|
+
path: urlPath,
|
|
76
|
+
statusCode: proxyRes.statusCode,
|
|
77
|
+
originalBytes: rawResponse.length,
|
|
78
|
+
scrubbedBytes: scrubbedResponse.length,
|
|
79
|
+
});
|
|
80
|
+
res.writeHead(proxyRes.statusCode ?? 200, {
|
|
81
|
+
'Content-Type': proxyRes.headers['content-type'] ?? 'application/json',
|
|
82
|
+
});
|
|
83
|
+
res.end(scrubbedResponse);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
proxyReq.on('error', (err) => {
|
|
87
|
+
logger.error('DD proxy: upstream request failed', {
|
|
88
|
+
task: 'persist-logs',
|
|
89
|
+
error: err.message,
|
|
90
|
+
path: urlPath,
|
|
91
|
+
});
|
|
92
|
+
res.writeHead(502);
|
|
93
|
+
res.end(JSON.stringify({ error: 'DD proxy upstream error' }));
|
|
94
|
+
});
|
|
95
|
+
if (requestBody) {
|
|
96
|
+
proxyReq.write(requestBody);
|
|
97
|
+
}
|
|
98
|
+
proxyReq.end();
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
server.on('error', reject);
|
|
102
|
+
server.listen(port, '127.0.0.1', () => {
|
|
103
|
+
logger.info('DD proxy started', {
|
|
104
|
+
task: 'persist-logs',
|
|
105
|
+
port,
|
|
106
|
+
target: DD_HOST,
|
|
107
|
+
});
|
|
108
|
+
resolve({
|
|
109
|
+
server,
|
|
110
|
+
stop: () => new Promise((resolveStop) => {
|
|
111
|
+
server.close(() => resolveStop());
|
|
112
|
+
}),
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { logger } from '../../core/logging.js';
|
|
4
|
+
import { invokePiPrompt } from '../../core/pi.js';
|
|
5
|
+
import { scrubPii } from '../../core/pii-scrubber.js';
|
|
6
|
+
import { loadPromptTemplateFile, resolvePromptFile } from '../../core/prompt-template.js';
|
|
7
|
+
import { startDdProxy } from './dd-proxy.js';
|
|
8
|
+
export const PERSIST_LOGS_PROVIDER = 'openai';
|
|
9
|
+
const TIMEOUT_MS = 20 * 60 * 1000; // 20 minutes — investigation can take a while
|
|
10
|
+
function buildPrompt(params, proxyPort) {
|
|
11
|
+
const ddApiReference = loadPromptTemplateFile({
|
|
12
|
+
fileName: resolvePromptFile(import.meta.url, 'persist-logs-dd-api-reference.md'),
|
|
13
|
+
promptLabel: 'persist-logs DD API reference',
|
|
14
|
+
});
|
|
15
|
+
const template = loadPromptTemplateFile({
|
|
16
|
+
fileName: resolvePromptFile(import.meta.url, 'persist-logs-investigation-prompt.md'),
|
|
17
|
+
promptLabel: 'persist-logs investigation prompt',
|
|
18
|
+
});
|
|
19
|
+
const scrubbedTitle = scrubPii(params.issueTitle);
|
|
20
|
+
const scrubbedBody = scrubPii(params.issueBody);
|
|
21
|
+
const scrubbedComments = params.comments
|
|
22
|
+
.map((c) => `### Comment by ${c.author}\n${scrubPii(c.body)}`)
|
|
23
|
+
.join('\n\n');
|
|
24
|
+
const proxyUrl = `http://127.0.0.1:${proxyPort}`;
|
|
25
|
+
const replacements = {
|
|
26
|
+
'{{PROXY_URL}}': proxyUrl,
|
|
27
|
+
'{{DD_API_REFERENCE}}': ddApiReference,
|
|
28
|
+
'{{REPO_DIR}}': params.repoDir,
|
|
29
|
+
'{{OUTPUT_DIR}}': params.outputDir,
|
|
30
|
+
'{{ISSUE_NUMBER}}': String(params.issueNumber),
|
|
31
|
+
'{{ISSUE_TITLE}}': scrubbedTitle,
|
|
32
|
+
'{{ISSUE_TITLE_ESCAPED}}': scrubbedTitle.replace(/"/g, '\\"'),
|
|
33
|
+
'{{ISSUE_BODY}}': scrubbedBody,
|
|
34
|
+
'{{COMMENTS_SECTION}}': scrubbedComments ? `## Comments\n\n${scrubbedComments}` : '',
|
|
35
|
+
};
|
|
36
|
+
let prompt = template;
|
|
37
|
+
for (const [placeholder, value] of Object.entries(replacements)) {
|
|
38
|
+
prompt = prompt.replaceAll(placeholder, value);
|
|
39
|
+
}
|
|
40
|
+
return prompt;
|
|
41
|
+
}
|
|
42
|
+
export async function runInvestigation(params) {
|
|
43
|
+
const DD_PROXY_PORT = 3100;
|
|
44
|
+
logger.info('Starting LLM investigation', {
|
|
45
|
+
task: 'persist-logs',
|
|
46
|
+
issueNumber: params.issueNumber,
|
|
47
|
+
repoDir: params.repoDir,
|
|
48
|
+
model: PERSIST_LOGS_PROVIDER,
|
|
49
|
+
});
|
|
50
|
+
// Ensure output directory exists
|
|
51
|
+
fs.mkdirSync(params.outputDir, { recursive: true });
|
|
52
|
+
// Start the DD proxy so the agent queries localhost; the proxy injects auth and scrubs PII.
|
|
53
|
+
const proxy = await startDdProxy({
|
|
54
|
+
port: DD_PROXY_PORT,
|
|
55
|
+
datadogApiKey: params.datadogApiKey,
|
|
56
|
+
datadogAppKey: params.datadogAppKey,
|
|
57
|
+
});
|
|
58
|
+
const prompt = buildPrompt(params, DD_PROXY_PORT);
|
|
59
|
+
let result;
|
|
60
|
+
try {
|
|
61
|
+
result = await invokePiPrompt({
|
|
62
|
+
provider: PERSIST_LOGS_PROVIDER,
|
|
63
|
+
apiKey: params.openaiApiKey,
|
|
64
|
+
prompt,
|
|
65
|
+
cwd: params.repoDir,
|
|
66
|
+
timeoutMs: TIMEOUT_MS,
|
|
67
|
+
capabilityPreset: 'shell-focused',
|
|
68
|
+
thinkingLevel: 'high',
|
|
69
|
+
onProgress: (event) => {
|
|
70
|
+
if (event.type === 'tool_start') {
|
|
71
|
+
logger.info('Investigation tool call', {
|
|
72
|
+
task: 'persist-logs',
|
|
73
|
+
tool: event.toolName,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
await proxy.stop();
|
|
81
|
+
logger.info('DD proxy stopped', { task: 'persist-logs' });
|
|
82
|
+
}
|
|
83
|
+
logger.info('Persist logs invocation result', {
|
|
84
|
+
task: 'persist-logs',
|
|
85
|
+
ok: result.ok,
|
|
86
|
+
toolUsage: result.toolUsage,
|
|
87
|
+
...(result.ok
|
|
88
|
+
? { outputLength: result.output.length }
|
|
89
|
+
: { error: result.error, timedOut: result.timedOut }),
|
|
90
|
+
});
|
|
91
|
+
if (!result.ok) {
|
|
92
|
+
if (result.timedOut) {
|
|
93
|
+
logger.error('LLM investigation timed out', {
|
|
94
|
+
task: 'persist-logs',
|
|
95
|
+
timeoutMs: TIMEOUT_MS,
|
|
96
|
+
});
|
|
97
|
+
return {
|
|
98
|
+
success: false,
|
|
99
|
+
totalLogs: 0,
|
|
100
|
+
error: `Investigation timed out after ${TIMEOUT_MS / 1000}s`,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
logger.error('LLM investigation failed', {
|
|
104
|
+
task: 'persist-logs',
|
|
105
|
+
error: result.error,
|
|
106
|
+
});
|
|
107
|
+
return { success: false, totalLogs: 0, error: result.error };
|
|
108
|
+
}
|
|
109
|
+
// Check for output files
|
|
110
|
+
const rawLogsPath = path.join(params.outputDir, `raw-logs-${params.issueNumber}.json`);
|
|
111
|
+
const analysisPath = path.join(params.outputDir, `analysis-${params.issueNumber}.md`);
|
|
112
|
+
const csvPath = path.join(params.outputDir, `logs-${params.issueNumber}.csv`);
|
|
113
|
+
const worklogPath = path.join(params.outputDir, `worklog-${params.issueNumber}.md`);
|
|
114
|
+
const hasRawLogs = fs.existsSync(rawLogsPath);
|
|
115
|
+
const hasAnalysis = fs.existsSync(analysisPath);
|
|
116
|
+
const hasCsv = fs.existsSync(csvPath);
|
|
117
|
+
const hasWorklog = fs.existsSync(worklogPath);
|
|
118
|
+
let totalLogs = 0;
|
|
119
|
+
if (hasRawLogs) {
|
|
120
|
+
try {
|
|
121
|
+
const raw = JSON.parse(fs.readFileSync(rawLogsPath, 'utf-8'));
|
|
122
|
+
totalLogs = raw.total_log_entries ?? 0;
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
logger.warn('Could not parse raw logs file', {
|
|
126
|
+
task: 'persist-logs',
|
|
127
|
+
path: rawLogsPath,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (!hasRawLogs) {
|
|
132
|
+
logger.warn('LLM investigation completed but raw-logs JSON not generated', {
|
|
133
|
+
task: 'persist-logs',
|
|
134
|
+
outputDir: params.outputDir,
|
|
135
|
+
hasAnalysis,
|
|
136
|
+
});
|
|
137
|
+
return { success: false, totalLogs: 0, error: 'raw-logs JSON not generated' };
|
|
138
|
+
}
|
|
139
|
+
logger.info('LLM investigation completed', {
|
|
140
|
+
task: 'persist-logs',
|
|
141
|
+
totalLogs,
|
|
142
|
+
hasRawLogs,
|
|
143
|
+
hasAnalysis,
|
|
144
|
+
hasCsv,
|
|
145
|
+
hasWorklog,
|
|
146
|
+
toolUsage: result.toolUsage,
|
|
147
|
+
});
|
|
148
|
+
return {
|
|
149
|
+
success: true,
|
|
150
|
+
rawLogsPath: hasRawLogs ? rawLogsPath : undefined,
|
|
151
|
+
analysisPath: hasAnalysis ? analysisPath : undefined,
|
|
152
|
+
csvPath: hasCsv ? csvPath : undefined,
|
|
153
|
+
worklogPath: hasWorklog ? worklogPath : undefined,
|
|
154
|
+
totalLogs,
|
|
155
|
+
};
|
|
156
|
+
}
|