@xn-intenton-z2a/agentic-lib 7.4.8 → 7.4.9
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/{src → .github}/agents/agent-apply-fix.md +10 -0
- package/{src → .github}/agents/agent-director.md +10 -0
- package/{src → .github}/agents/agent-discovery.md +8 -0
- package/{src → .github}/agents/agent-discussion-bot.md +9 -0
- package/{src → .github}/agents/agent-issue-resolution.md +12 -0
- package/{src → .github}/agents/agent-iterate.md +8 -0
- package/{src → .github}/agents/agent-maintain-features.md +8 -0
- package/{src → .github}/agents/agent-maintain-library.md +7 -0
- package/{src → .github}/agents/agent-review-issue.md +8 -0
- package/{src → .github}/agents/agent-supervisor.md +9 -0
- package/.github/workflows/agentic-lib-test.yml +4 -2
- package/.github/workflows/agentic-lib-workflow.yml +70 -26
- package/README.md +5 -7
- package/agentic-lib.toml +16 -38
- package/bin/agentic-lib.js +49 -60
- package/package.json +3 -4
- package/src/actions/agentic-step/action.yml +1 -1
- package/src/actions/agentic-step/copilot.js +0 -5
- package/src/actions/agentic-step/index.js +8 -1
- package/src/actions/agentic-step/logging.js +14 -2
- package/src/actions/agentic-step/tasks/direct.js +86 -65
- package/src/actions/agentic-step/tasks/discussions.js +198 -264
- package/src/actions/agentic-step/tasks/enhance-issue.js +84 -33
- package/src/actions/agentic-step/tasks/fix-code.js +111 -57
- package/src/actions/agentic-step/tasks/maintain-features.js +69 -52
- package/src/actions/agentic-step/tasks/maintain-library.js +57 -19
- package/src/actions/agentic-step/tasks/resolve-issue.js +43 -18
- package/src/actions/agentic-step/tasks/review-issue.js +117 -117
- package/src/actions/agentic-step/tasks/supervise.js +140 -151
- package/src/actions/agentic-step/tasks/transform.js +106 -258
- package/src/copilot/agents.js +2 -2
- package/src/copilot/config.js +2 -18
- package/src/copilot/{hybrid-session.js → copilot-session.js} +39 -7
- package/src/copilot/github-tools.js +514 -0
- package/src/copilot/guards.js +1 -1
- package/src/copilot/session.js +0 -141
- package/src/copilot/tools.js +4 -0
- package/src/iterate.js +1 -1
- package/src/scripts/push-to-logs.sh +1 -1
- package/src/seeds/zero-SCREENSHOT_INDEX.png +0 -0
- package/src/seeds/zero-package.json +1 -1
- package/src/agents/agentic-lib.yml +0 -66
- package/src/copilot/context.js +0 -457
- package/src/mcp/server.js +0 -830
- /package/{src → .github}/agents/agent-ready-issue.md +0 -0
package/bin/agentic-lib.js
CHANGED
|
@@ -37,7 +37,7 @@ const TASK_AGENT_MAP = {
|
|
|
37
37
|
"maintain-library": "agent-maintain-library",
|
|
38
38
|
};
|
|
39
39
|
const INIT_COMMANDS = ["init", "update", "reset"];
|
|
40
|
-
const ALL_COMMANDS = [...INIT_COMMANDS, ...TASK_COMMANDS, "version", "
|
|
40
|
+
const ALL_COMMANDS = [...INIT_COMMANDS, ...TASK_COMMANDS, "version", "iterate"];
|
|
41
41
|
|
|
42
42
|
const HELP = `
|
|
43
43
|
@xn-intenton-z2a/agentic-lib — Agentic Coding Systems SDK
|
|
@@ -61,9 +61,6 @@ Iterator:
|
|
|
61
61
|
iterate --here Discover the project and generate a MISSION.md, then iterate
|
|
62
62
|
iterate --list-missions List available built-in mission seeds
|
|
63
63
|
|
|
64
|
-
MCP Server:
|
|
65
|
-
mcp Start MCP server (for Claude Code, Cursor, etc.)
|
|
66
|
-
|
|
67
64
|
Options:
|
|
68
65
|
--purge Full reset — clear features, activity log, source code
|
|
69
66
|
--reseed Clear features + activity log (keep source code)
|
|
@@ -135,13 +132,6 @@ const discussionUrl = discussionIdx >= 0 ? flags[discussionIdx + 1] : "";
|
|
|
135
132
|
|
|
136
133
|
// ─── Task Commands ───────────────────────────────────────────────────
|
|
137
134
|
|
|
138
|
-
if (command === "mcp") {
|
|
139
|
-
const { startServer } = await import("../src/mcp/server.js");
|
|
140
|
-
await startServer();
|
|
141
|
-
// Server runs until stdin closes — don't exit
|
|
142
|
-
await new Promise(() => {}); // block forever
|
|
143
|
-
}
|
|
144
|
-
|
|
145
135
|
if (command === "iterate") {
|
|
146
136
|
process.exit(await runIterate());
|
|
147
137
|
}
|
|
@@ -215,10 +205,10 @@ async function runIterate() {
|
|
|
215
205
|
console.log("");
|
|
216
206
|
|
|
217
207
|
const discoveryPrompt = loadAgentPrompt("agent-discovery");
|
|
218
|
-
const {
|
|
208
|
+
const { runCopilotSession } = await import("../src/copilot/copilot-session.js");
|
|
219
209
|
const effectiveModel = model || config.model || "gpt-5-mini";
|
|
220
210
|
|
|
221
|
-
const discoveryResult = await
|
|
211
|
+
const discoveryResult = await runCopilotSession({
|
|
222
212
|
workspacePath: target,
|
|
223
213
|
model: effectiveModel,
|
|
224
214
|
tuning: config.tuning || {},
|
|
@@ -298,8 +288,8 @@ async function runIterate() {
|
|
|
298
288
|
);
|
|
299
289
|
}
|
|
300
290
|
|
|
301
|
-
const {
|
|
302
|
-
const {
|
|
291
|
+
const { runCopilotSession } = await import("../src/copilot/copilot-session.js");
|
|
292
|
+
const { readOptionalFile } = await import("../src/copilot/session.js");
|
|
303
293
|
|
|
304
294
|
// Load agent prompt: --agent flag > default agent-iterate
|
|
305
295
|
const agentName = agentFlag || "agent-iterate";
|
|
@@ -322,32 +312,26 @@ async function runIterate() {
|
|
|
322
312
|
if (discussionUrl) console.log(`Discussion: ${discussionUrl}`);
|
|
323
313
|
console.log("");
|
|
324
314
|
|
|
325
|
-
//
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
})
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
// Build context-aware user prompt
|
|
341
|
-
const { prompt: userPrompt } = buildUserPrompt(agentName, localContext, githubContext, {
|
|
342
|
-
tuning: config.tuning,
|
|
343
|
-
config,
|
|
344
|
-
});
|
|
315
|
+
// Build lean prompt — the model explores via tools (read_file, list_files, run_command)
|
|
316
|
+
const missionPath = resolve(target, config.paths?.mission?.path || "MISSION.md");
|
|
317
|
+
const missionContent = readOptionalFile(missionPath, 2000) || "(no mission defined)";
|
|
318
|
+
const userPrompt = [
|
|
319
|
+
"## Mission",
|
|
320
|
+
missionContent,
|
|
321
|
+
"",
|
|
322
|
+
"## Your Task",
|
|
323
|
+
"Use list_files to explore the repository, read_file to examine source code and tests,",
|
|
324
|
+
"and run_command to run the test suite. Write code to advance the mission.",
|
|
325
|
+
...(issueNumber ? [``, `Focus on issue #${issueNumber}.`] : []),
|
|
326
|
+
...(prNumber ? [``, `Focus on PR #${prNumber}.`] : []),
|
|
327
|
+
...(discussionUrl ? [``, `Discussion context: ${discussionUrl}`] : []),
|
|
328
|
+
].join("\n");
|
|
345
329
|
|
|
346
330
|
// Derive maxToolCalls from transformation budget
|
|
347
331
|
const budget = config.transformationBudget || 0;
|
|
348
332
|
const effectiveMaxToolCalls = budget > 0 ? budget * 20 : undefined;
|
|
349
333
|
|
|
350
|
-
const result = await
|
|
334
|
+
const result = await runCopilotSession({
|
|
351
335
|
workspacePath: target,
|
|
352
336
|
model: effectiveModel,
|
|
353
337
|
tuning: config.tuning || {},
|
|
@@ -423,31 +407,31 @@ async function runTask(taskName) {
|
|
|
423
407
|
|
|
424
408
|
try {
|
|
425
409
|
const { loadAgentPrompt } = await import("../src/copilot/agents.js");
|
|
426
|
-
const {
|
|
427
|
-
const {
|
|
410
|
+
const { runCopilotSession } = await import("../src/copilot/copilot-session.js");
|
|
411
|
+
const { readOptionalFile } = await import("../src/copilot/session.js");
|
|
428
412
|
|
|
429
413
|
const agentPrompt = loadAgentPrompt(agentName);
|
|
430
|
-
const localContext = gatherLocalContext(target, config);
|
|
431
|
-
|
|
432
|
-
let githubContext;
|
|
433
|
-
if (issueNumber || prNumber) {
|
|
434
|
-
githubContext = gatherGitHubContext({
|
|
435
|
-
issueNumber: issueNumber || undefined,
|
|
436
|
-
prNumber: prNumber || undefined,
|
|
437
|
-
workspacePath: target,
|
|
438
|
-
});
|
|
439
|
-
}
|
|
440
414
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
415
|
+
// Build lean prompt — the model explores via tools (read_file, list_files, run_command)
|
|
416
|
+
const missionPath = resolve(target, config.paths?.mission?.path || config.paths?.mission || "MISSION.md");
|
|
417
|
+
const missionContent = readOptionalFile(missionPath, 2000) || "(no mission defined)";
|
|
418
|
+
const userPrompt = [
|
|
419
|
+
"## Mission",
|
|
420
|
+
missionContent,
|
|
421
|
+
"",
|
|
422
|
+
"## Your Task",
|
|
423
|
+
"Use list_files to explore the repository, read_file to examine source code and tests,",
|
|
424
|
+
"and run_command to run the test suite. Write code to advance the mission.",
|
|
425
|
+
...(issueNumber ? [``, `Focus on issue #${issueNumber}.`] : []),
|
|
426
|
+
...(prNumber ? [``, `Focus on PR #${prNumber}.`] : []),
|
|
427
|
+
...(discussionUrl ? [``, `Discussion context: ${discussionUrl}`] : []),
|
|
428
|
+
].join("\n");
|
|
445
429
|
|
|
446
430
|
// Derive maxToolCalls from transformation budget (budget × 20, or unlimited)
|
|
447
431
|
const budget = config.transformationBudget || 0;
|
|
448
432
|
const effectiveMaxToolCalls = budget > 0 ? budget * 20 : undefined;
|
|
449
433
|
|
|
450
|
-
const result = await
|
|
434
|
+
const result = await runCopilotSession({
|
|
451
435
|
workspacePath: target,
|
|
452
436
|
model: effectiveModel,
|
|
453
437
|
tuning: config.tuning || {},
|
|
@@ -469,12 +453,6 @@ async function runTask(taskName) {
|
|
|
469
453
|
console.log(`Tool calls: ${result.toolCalls}`);
|
|
470
454
|
console.log(`Tokens: ${tokensUsed} (in=${result.tokensIn} out=${result.tokensOut})`);
|
|
471
455
|
if (result.narrative) console.log(`Narrative: ${result.narrative}`);
|
|
472
|
-
if (promptBudget) {
|
|
473
|
-
console.log("Prompt budget:");
|
|
474
|
-
for (const entry of promptBudget) {
|
|
475
|
-
console.log(` ${entry.section}: ${entry.size} chars, ${entry.files} files ${entry.notes}`);
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
456
|
console.log("");
|
|
479
457
|
return result.success ? 0 : 1;
|
|
480
458
|
} catch (err) {
|
|
@@ -575,6 +553,16 @@ function initActions(agenticDir) {
|
|
|
575
553
|
}
|
|
576
554
|
}
|
|
577
555
|
|
|
556
|
+
function initAgents(dstDir) {
|
|
557
|
+
console.log("\n--- Agents ---");
|
|
558
|
+
const agentsSrcDir = resolve(pkgRoot, ".github/agents");
|
|
559
|
+
if (!existsSync(agentsSrcDir)) return;
|
|
560
|
+
for (const entry of readdirSync(agentsSrcDir, { withFileTypes: true })) {
|
|
561
|
+
if (!entry.isFile()) continue;
|
|
562
|
+
initCopyFile(resolve(agentsSrcDir, entry.name), resolve(dstDir, entry.name), `agents/${entry.name}`);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
578
566
|
function initDirContents(srcSubdir, dstDir, label, excludeFiles = []) {
|
|
579
567
|
console.log(`\n--- ${label} ---`);
|
|
580
568
|
const dir = resolve(srcDir, srcSubdir);
|
|
@@ -770,6 +758,7 @@ function initPurge(seedsDir, missionName, initTimestamp) {
|
|
|
770
758
|
"zero-package.json": "package.json",
|
|
771
759
|
"zero-README.md": "README.md",
|
|
772
760
|
"zero-.gitignore": ".gitignore",
|
|
761
|
+
"zero-SCREENSHOT_INDEX.png": "SCREENSHOT_INDEX.png",
|
|
773
762
|
};
|
|
774
763
|
for (const [seedFile, targetRel] of Object.entries(SEED_MAP)) {
|
|
775
764
|
const src = resolve(seedsDir, seedFile);
|
|
@@ -1271,7 +1260,7 @@ function runInit() {
|
|
|
1271
1260
|
initWorkflows();
|
|
1272
1261
|
initActions(agenticDir);
|
|
1273
1262
|
initDirContents("copilot", resolve(agenticDir, "copilot"), "Copilot (shared modules)");
|
|
1274
|
-
|
|
1263
|
+
initAgents(resolve(target, ".github/agents"));
|
|
1275
1264
|
// Remove stale legacy agents directory
|
|
1276
1265
|
const legacyAgentsDir = resolve(agenticDir, "agents");
|
|
1277
1266
|
if (existsSync(legacyAgentsDir)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xn-intenton-z2a/agentic-lib",
|
|
3
|
-
"version": "7.4.
|
|
3
|
+
"version": "7.4.9",
|
|
4
4
|
"description": "Agentic-lib Agentic Coding Systems SDK powering automated GitHub workflows.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -79,10 +79,9 @@
|
|
|
79
79
|
"src/actions/agentic-step/tasks/",
|
|
80
80
|
"src/actions/commit-if-changed/",
|
|
81
81
|
"src/actions/setup-npmrc/",
|
|
82
|
-
"
|
|
82
|
+
".github/agents/",
|
|
83
83
|
"src/seeds/",
|
|
84
|
-
"src/scripts/"
|
|
85
|
-
"src/mcp/"
|
|
84
|
+
"src/scripts/"
|
|
86
85
|
],
|
|
87
86
|
"overrides": {
|
|
88
87
|
"minimatch": ">=10.2.3",
|
|
@@ -16,7 +16,7 @@ inputs:
|
|
|
16
16
|
maintain-library, enhance-issue, review-issue, discussions, supervise
|
|
17
17
|
required: true
|
|
18
18
|
config:
|
|
19
|
-
description: "Path to agentic-lib.
|
|
19
|
+
description: "Path to agentic-lib.toml configuration file"
|
|
20
20
|
required: false
|
|
21
21
|
default: "agentic-lib.toml"
|
|
22
22
|
instructions:
|
|
@@ -39,7 +39,6 @@ import {
|
|
|
39
39
|
scanDirectory as _scanDirectory,
|
|
40
40
|
buildClientOptions as _buildClientOptions,
|
|
41
41
|
logTuningParam as _logTuningParam,
|
|
42
|
-
runCopilotTask as _runCopilotTask,
|
|
43
42
|
} from "../../copilot/session.js";
|
|
44
43
|
|
|
45
44
|
export function readOptionalFile(filePath, limit) {
|
|
@@ -57,7 +56,3 @@ export function buildClientOptions(githubToken) {
|
|
|
57
56
|
export function logTuningParam(param, value, profileName, model, clip) {
|
|
58
57
|
return _logTuningParam(param, value, profileName, model, clip, actionsLogger);
|
|
59
58
|
}
|
|
60
|
-
|
|
61
|
-
export async function runCopilotTask(options) {
|
|
62
|
-
return _runCopilotTask({ ...options, logger: actionsLogger });
|
|
63
|
-
}
|
|
@@ -9,7 +9,7 @@ import * as core from "@actions/core";
|
|
|
9
9
|
import * as github from "@actions/github";
|
|
10
10
|
import { loadConfig, getWritablePaths } from "./config-loader.js";
|
|
11
11
|
import { logActivity, generateClosingNotes } from "./logging.js";
|
|
12
|
-
import { readFileSync } from "fs";
|
|
12
|
+
import { readFileSync, existsSync } from "fs";
|
|
13
13
|
import {
|
|
14
14
|
buildMissionMetrics, buildMissionReadiness,
|
|
15
15
|
computeTransformationCost, readCumulativeCost, buildLimitsStatus,
|
|
@@ -60,6 +60,12 @@ async function run() {
|
|
|
60
60
|
const handler = TASKS[task];
|
|
61
61
|
if (!handler) throw new Error(`Unknown task: ${task}. Available: ${Object.keys(TASKS).join(", ")}`);
|
|
62
62
|
|
|
63
|
+
// Resolve log and screenshot paths (fetched from agentic-lib-logs branch by workflow)
|
|
64
|
+
const logFile = config.intentionBot?.intentionFilepath || "intenti\u00F6n.md";
|
|
65
|
+
const screenshotFile = config.intentionBot?.screenshotFile || "SCREENSHOT_INDEX.png";
|
|
66
|
+
const logFilePath = existsSync(logFile) ? logFile : null;
|
|
67
|
+
const screenshotFilePath = existsSync(screenshotFile) ? screenshotFile : null;
|
|
68
|
+
|
|
63
69
|
const context = {
|
|
64
70
|
task, config, instructions, issueNumber, writablePaths, testCommand, model,
|
|
65
71
|
prNumber: core.getInput("pr-number"),
|
|
@@ -68,6 +74,7 @@ async function run() {
|
|
|
68
74
|
commentCreatedAt: core.getInput("comment-created-at"),
|
|
69
75
|
octokit: github.getOctokit(process.env.GITHUB_TOKEN),
|
|
70
76
|
repo: github.context.repo, github: github.context,
|
|
77
|
+
logFilePath, screenshotFilePath,
|
|
71
78
|
};
|
|
72
79
|
|
|
73
80
|
const startTime = Date.now();
|
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
// Appends structured entries to the intentïon.md activity log,
|
|
6
6
|
// including commit URLs and safety-check outcomes.
|
|
7
7
|
|
|
8
|
-
import { writeFileSync, readFileSync, appendFileSync, existsSync, mkdirSync } from "fs";
|
|
9
|
-
import { dirname } from "path";
|
|
8
|
+
import { writeFileSync, readFileSync, appendFileSync, existsSync, mkdirSync, copyFileSync } from "fs";
|
|
9
|
+
import { dirname, basename } from "path";
|
|
10
|
+
import { join } from "path";
|
|
10
11
|
import * as core from "@actions/core";
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -158,6 +159,17 @@ export function logActivity({
|
|
|
158
159
|
} else {
|
|
159
160
|
writeFileSync(filepath, `# intentïon Activity Log\n${entry}`);
|
|
160
161
|
}
|
|
162
|
+
|
|
163
|
+
// Write ASCII fallback copy (intention.md) for systems that can't handle UTF-8 filenames
|
|
164
|
+
const name = basename(filepath);
|
|
165
|
+
if (name !== "intention.md" && name.includes("intenti")) {
|
|
166
|
+
const fallbackPath = join(dirname(filepath), "intention.md");
|
|
167
|
+
try {
|
|
168
|
+
copyFileSync(filepath, fallbackPath);
|
|
169
|
+
} catch {
|
|
170
|
+
// Best-effort — don't fail the log if the copy fails
|
|
171
|
+
}
|
|
172
|
+
}
|
|
161
173
|
}
|
|
162
174
|
|
|
163
175
|
/**
|
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
// Copyright (C) 2025-2026 Polycode Limited
|
|
3
3
|
// tasks/direct.js — Director: mission-complete/failed evaluation via LLM
|
|
4
4
|
//
|
|
5
|
-
//
|
|
6
|
-
// to
|
|
5
|
+
// Uses runCopilotSession with lean prompts: the model reads source files
|
|
6
|
+
// via tools to determine mission status and produce a structured evaluation.
|
|
7
7
|
// The director does NOT dispatch workflows or create issues — that's the supervisor's job.
|
|
8
8
|
|
|
9
9
|
import * as core from "@actions/core";
|
|
10
10
|
import { existsSync, readFileSync, writeFileSync, readdirSync, statSync } from "fs";
|
|
11
|
-
import {
|
|
11
|
+
import { readOptionalFile, scanDirectory, filterIssues, extractNarrative, NARRATIVE_INSTRUCTION } from "../copilot.js";
|
|
12
|
+
import { runCopilotSession } from "../../../copilot/copilot-session.js";
|
|
13
|
+
import { createGitHubTools, createGitTools } from "../../../copilot/github-tools.js";
|
|
12
14
|
|
|
13
15
|
/**
|
|
14
16
|
* Count TODO comments recursively in a directory.
|
|
@@ -98,7 +100,7 @@ function buildMetricAssessment(ctx, config) {
|
|
|
98
100
|
}
|
|
99
101
|
|
|
100
102
|
/**
|
|
101
|
-
* Build the director prompt.
|
|
103
|
+
* Build the director prompt (lean version — model explores via tools).
|
|
102
104
|
*/
|
|
103
105
|
function buildPrompt(ctx, agentInstructions, metricAssessment) {
|
|
104
106
|
return [
|
|
@@ -114,35 +116,21 @@ function buildPrompt(ctx, agentInstructions, metricAssessment) {
|
|
|
114
116
|
"### Mission-Complete Metrics",
|
|
115
117
|
metricAssessment.table,
|
|
116
118
|
"",
|
|
117
|
-
"## Repository
|
|
118
|
-
|
|
119
|
-
ctx.
|
|
119
|
+
"## Repository Summary",
|
|
120
|
+
`Open issues: ${ctx.issuesSummary.length}`,
|
|
121
|
+
`Recently closed issues: ${ctx.recentlyClosedSummary.length}`,
|
|
122
|
+
`Open PRs: ${ctx.prsSummary.length}`,
|
|
123
|
+
`Dedicated test files: ${ctx.dedicatedTestCount}`,
|
|
124
|
+
`Source TODOs: ${ctx.sourceTodoCount}`,
|
|
125
|
+
`Transformation budget: ${ctx.cumulativeTransformationCost}/${ctx.transformationBudget || "unlimited"}`,
|
|
120
126
|
"",
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
"",
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
"",
|
|
127
|
-
...(ctx.sourceExports?.length > 0
|
|
128
|
-
? [
|
|
129
|
-
`### Source Exports`,
|
|
130
|
-
...ctx.sourceExports.map((e) => `- ${e}`),
|
|
131
|
-
"",
|
|
132
|
-
]
|
|
133
|
-
: []),
|
|
134
|
-
`### Test Coverage`,
|
|
135
|
-
ctx.dedicatedTestCount > 0
|
|
136
|
-
? `Dedicated test files (${ctx.dedicatedTestCount}): ${ctx.dedicatedTestFiles.join(", ")}`
|
|
137
|
-
: "**No dedicated test files found.**",
|
|
138
|
-
"",
|
|
139
|
-
`### Source TODO Count: ${ctx.sourceTodoCount}`,
|
|
140
|
-
"",
|
|
141
|
-
`### Transformation Budget: ${ctx.cumulativeTransformationCost}/${ctx.transformationBudget || "unlimited"}`,
|
|
142
|
-
"",
|
|
143
|
-
`### Recent Activity`,
|
|
144
|
-
ctx.recentActivity || "none",
|
|
127
|
+
"## Your Task",
|
|
128
|
+
"Use list_issues and list_prs to review open work items.",
|
|
129
|
+
"Use read_file to inspect source code and tests for completeness.",
|
|
130
|
+
"Use git_diff or git_status for additional context if needed.",
|
|
131
|
+
"Then call report_director_decision with your determination.",
|
|
145
132
|
"",
|
|
133
|
+
"**You MUST call report_director_decision exactly once.**",
|
|
146
134
|
].join("\n");
|
|
147
135
|
}
|
|
148
136
|
|
|
@@ -240,13 +228,12 @@ async function executeMissionFailed(octokit, repo, reason) {
|
|
|
240
228
|
* @returns {Promise<Object>} Result with outcome, tokensUsed, model
|
|
241
229
|
*/
|
|
242
230
|
export async function direct(context) {
|
|
243
|
-
const { octokit, repo, config, instructions, model } = context;
|
|
231
|
+
const { octokit, repo, config, instructions, model, logFilePath, screenshotFilePath } = context;
|
|
244
232
|
const t = config.tuning || {};
|
|
245
233
|
|
|
246
234
|
// --- Gather context (similar to supervisor but focused on metrics) ---
|
|
247
235
|
const mission = readOptionalFile(config.paths.mission.path);
|
|
248
236
|
const intentionLogFull = readOptionalFile(config.intentionBot.intentionFilepath);
|
|
249
|
-
const recentActivity = intentionLogFull.split("\n").slice(-20).join("\n");
|
|
250
237
|
|
|
251
238
|
const costMatches = intentionLogFull.matchAll(/\*\*agentic-lib transformation cost:\*\* (\d+)/g);
|
|
252
239
|
const cumulativeTransformationCost = [...costMatches].reduce((sum, m) => sum + parseInt(m[1], 10), 0);
|
|
@@ -271,7 +258,7 @@ export async function direct(context) {
|
|
|
271
258
|
const initTimestamp = config.init?.timestamp || null;
|
|
272
259
|
|
|
273
260
|
const { data: openIssues } = await octokit.rest.issues.listForRepo({
|
|
274
|
-
...repo, state: "open", per_page:
|
|
261
|
+
...repo, state: "open", per_page: 20, sort: "created", direction: "asc",
|
|
275
262
|
});
|
|
276
263
|
const issuesOnly = openIssues.filter((i) => !i.pull_request);
|
|
277
264
|
const filteredIssues = filterIssues(issuesOnly, { staleDays: t.staleDays || 30, initTimestamp });
|
|
@@ -307,7 +294,6 @@ export async function direct(context) {
|
|
|
307
294
|
closeReason = "RESOLVED";
|
|
308
295
|
}
|
|
309
296
|
}
|
|
310
|
-
// Check for automerge closure (issue has "merged" label — set by ci-automerge)
|
|
311
297
|
if (closeReason !== "RESOLVED") {
|
|
312
298
|
const issueLabels = ci.labels.map((l) => (typeof l === "string" ? l : l.name));
|
|
313
299
|
if (issueLabels.includes("merged")) {
|
|
@@ -328,23 +314,6 @@ export async function direct(context) {
|
|
|
328
314
|
});
|
|
329
315
|
const prsSummary = openPRs.map((pr) => `#${pr.number}: ${pr.title} (${pr.head.ref})`);
|
|
330
316
|
|
|
331
|
-
// Source exports
|
|
332
|
-
let sourceExports = [];
|
|
333
|
-
try {
|
|
334
|
-
const sourcePath = config.paths.source?.path || "src/lib/";
|
|
335
|
-
if (existsSync(sourcePath)) {
|
|
336
|
-
const sourceFiles = scanDirectory(sourcePath, [".js", ".ts"], { limit: 5 });
|
|
337
|
-
for (const sf of sourceFiles) {
|
|
338
|
-
const content = readFileSync(sf.path, "utf8");
|
|
339
|
-
const exports = [...content.matchAll(/export\s+(?:async\s+)?(?:function|const|let|var|class)\s+(\w+)/g)]
|
|
340
|
-
.map((m) => m[1]);
|
|
341
|
-
if (exports.length > 0) {
|
|
342
|
-
sourceExports.push(`${sf.name}: ${exports.join(", ")}`);
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
} catch { /* ignore */ }
|
|
347
|
-
|
|
348
317
|
// Dedicated tests
|
|
349
318
|
const { dedicatedTestCount, dedicatedTestFiles } = detectDedicatedTests();
|
|
350
319
|
|
|
@@ -357,12 +326,10 @@ export async function direct(context) {
|
|
|
357
326
|
// Build context
|
|
358
327
|
const ctx = {
|
|
359
328
|
mission,
|
|
360
|
-
recentActivity,
|
|
361
329
|
issuesSummary,
|
|
362
330
|
recentlyClosedSummary,
|
|
363
331
|
resolvedCount,
|
|
364
332
|
prsSummary,
|
|
365
|
-
sourceExports,
|
|
366
333
|
dedicatedTestCount,
|
|
367
334
|
dedicatedTestFiles,
|
|
368
335
|
sourceTodoCount,
|
|
@@ -374,20 +341,74 @@ export async function direct(context) {
|
|
|
374
341
|
const metricAssessment = buildMetricAssessment(ctx, config);
|
|
375
342
|
core.info(`Metric assessment: ${metricAssessment.assessment}`);
|
|
376
343
|
|
|
377
|
-
// --- LLM decision ---
|
|
344
|
+
// --- LLM decision via hybrid session ---
|
|
378
345
|
const agentInstructions = instructions || "You are the director. Evaluate mission readiness.";
|
|
379
346
|
const prompt = buildPrompt(ctx, agentInstructions, metricAssessment);
|
|
380
347
|
|
|
381
|
-
const
|
|
348
|
+
const systemPrompt =
|
|
349
|
+
"You are the director of an autonomous coding repository. Your job is to evaluate whether the mission is complete, failed, or in progress. You produce a structured assessment — you do NOT dispatch workflows or create issues." +
|
|
350
|
+
NARRATIVE_INSTRUCTION;
|
|
351
|
+
|
|
352
|
+
// Shared mutable state to capture the decision
|
|
353
|
+
const decisionResult = { decision: "in-progress", reason: "", analysis: "" };
|
|
354
|
+
|
|
355
|
+
const createTools = (defineTool, _wp, logger) => {
|
|
356
|
+
const ghTools = createGitHubTools(octokit, repo, defineTool, logger);
|
|
357
|
+
const gitTools = createGitTools(defineTool, logger);
|
|
358
|
+
|
|
359
|
+
const reportDecision = defineTool("report_director_decision", {
|
|
360
|
+
description: "Report the director's mission evaluation decision. Call this exactly once.",
|
|
361
|
+
parameters: {
|
|
362
|
+
type: "object",
|
|
363
|
+
properties: {
|
|
364
|
+
decision: {
|
|
365
|
+
type: "string",
|
|
366
|
+
enum: ["mission-complete", "mission-failed", "in-progress"],
|
|
367
|
+
description: "The mission status decision",
|
|
368
|
+
},
|
|
369
|
+
reason: { type: "string", description: "One-line summary of the decision" },
|
|
370
|
+
analysis: { type: "string", description: "Detailed analysis of the mission state" },
|
|
371
|
+
},
|
|
372
|
+
required: ["decision", "reason"],
|
|
373
|
+
},
|
|
374
|
+
handler: async ({ decision, reason, analysis }) => {
|
|
375
|
+
decisionResult.decision = decision;
|
|
376
|
+
decisionResult.reason = reason || "";
|
|
377
|
+
decisionResult.analysis = analysis || "";
|
|
378
|
+
return { textResultForLlm: `Decision recorded: ${decision}` };
|
|
379
|
+
},
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
return [...ghTools, ...gitTools, reportDecision];
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
const attachments = [];
|
|
386
|
+
if (logFilePath) attachments.push({ type: "file", path: logFilePath });
|
|
387
|
+
if (screenshotFilePath) attachments.push({ type: "file", path: screenshotFilePath });
|
|
388
|
+
|
|
389
|
+
const result = await runCopilotSession({
|
|
390
|
+
workspacePath: process.cwd(),
|
|
382
391
|
model,
|
|
383
|
-
systemMessage:
|
|
384
|
-
"You are the director of an autonomous coding repository. Your job is to evaluate whether the mission is complete, failed, or in progress. You produce a structured assessment — you do NOT dispatch workflows or create issues.",
|
|
385
|
-
prompt,
|
|
386
|
-
writablePaths: [],
|
|
387
392
|
tuning: t,
|
|
393
|
+
agentPrompt: systemPrompt,
|
|
394
|
+
userPrompt: prompt,
|
|
395
|
+
writablePaths: [],
|
|
396
|
+
createTools,
|
|
397
|
+
attachments,
|
|
398
|
+
excludedTools: ["write_file", "run_command", "run_tests", "dispatch_workflow", "close_issue", "label_issue", "post_discussion_comment", "create_issue", "comment_on_issue"],
|
|
399
|
+
logger: { info: core.info, warning: core.warning, error: core.error, debug: core.debug },
|
|
388
400
|
});
|
|
389
401
|
|
|
390
|
-
const
|
|
402
|
+
const tokensUsed = result.tokensIn + result.tokensOut;
|
|
403
|
+
|
|
404
|
+
// Extract decision — prefer tool result, fall back to text parsing
|
|
405
|
+
let { decision, reason, analysis } = decisionResult;
|
|
406
|
+
if (decision === "in-progress" && !decisionResult.reason && result.agentMessage) {
|
|
407
|
+
const parsed = parseDirectorResponse(result.agentMessage);
|
|
408
|
+
decision = parsed.decision;
|
|
409
|
+
reason = parsed.reason;
|
|
410
|
+
analysis = parsed.analysis;
|
|
411
|
+
}
|
|
391
412
|
core.info(`Director decision: ${decision} — ${reason}`);
|
|
392
413
|
|
|
393
414
|
// Execute the decision
|
|
@@ -414,12 +435,12 @@ export async function direct(context) {
|
|
|
414
435
|
return {
|
|
415
436
|
outcome,
|
|
416
437
|
tokensUsed,
|
|
417
|
-
inputTokens,
|
|
418
|
-
outputTokens,
|
|
419
|
-
cost,
|
|
438
|
+
inputTokens: result.tokensIn,
|
|
439
|
+
outputTokens: result.tokensOut,
|
|
440
|
+
cost: 0,
|
|
420
441
|
model,
|
|
421
442
|
details: `Decision: ${decision}\nReason: ${reason}\nAnalysis: ${analysis.substring(0, 300)}`,
|
|
422
|
-
narrative: `Director: ${reason}`,
|
|
443
|
+
narrative: result.narrative || `Director: ${reason}`,
|
|
423
444
|
metricAssessment: metricAssessment.assessment,
|
|
424
445
|
directorAnalysis: analysis,
|
|
425
446
|
dedicatedTestCount,
|